Common .NET Security Mistakes That Will Get You Pwned

Security isn’t an afterthought - it’s a fundamental part of software development and needs to be included at all stages of the SDLC.

Common .NET Security Mistakes That Will Get You Pwned

Security isn’t optional. It’s not something you slap on at the end of a project after everything else is working. It needs to be baked into your development process from the start. Yet, time and time again, I see developers - sometimes even experienced ones - making the same security mistakes in .NET applications. Let’s go through some of the most common pitfalls and, more importantly, how to avoid them.

1. Storing Passwords in Plain Text

If you’re storing passwords as plain text, stop. Right now. If you do this, and you can sleep at night, you need to quit your job immediately and change career. There is absolutely no excuse for this. If an attacker gains access to your database, they shouldn’t be able to see users’ actual passwords. Instead:

  • Always hash passwords using a strong hashing algorithm like bcrypt or Argon2.
  • Never use MD5 or SHA1 - they are outdated and easily cracked.
  • Use a proper password management library like ASP.NET Identity, which handles password hashing and salting correctly.

Remember it's not just the user data in your application that is exposed. Users often use the same password on multiple sites. There is never any excuse for storing passwords in plain text. If you do this, I will fight you!

2. Leaving Debug Endpoints Open in Production

I get it - debugging is a pain. It’s tempting to leave an admin-only backdoor to poke around in production when things go wrong. But if you do this, you’re basically leaving a “Hack Me” sign on your server. Attackers actively look for these endpoints.

What to do instead:

  • Never deploy with debugging tools like MiniProfiler, Serilog’s Seq, or dotnet-dump active.
  • Disable debugging and tracing in production (<compilation debug="false" /> in Web.config).
  • Ensure any debugging or admin tools are locked down behind authentication and never exposed publicly.

3. Not Properly Validating User Input

If you’re not validating user input, you might as well hand your database over to an attacker. SQL injection is still one of the most common vulnerabilities, and it happens when you trust user input too much.

How to avoid SQL injection:

  • Always use parameterized queries or ORMs like Entity Framework instead of string concatenation.
  • Validate and sanitize all user input - never assume it’s safe.
  • Use Stored Procedures where applicable, ensuring they do not concatenate raw user input.
  • Consider Entity Framework Core’s logging to monitor for raw SQL execution risks.

4. Securing APIs with Proper Authentication & Authorization

Your API is not special. If you’re exposing endpoints without proper authentication and authorization, you’re basically giving attackers free access to sensitive data.

Best practices:

  • Always secure APIs with OAuth 2.0 or JWT tokens -don’t rely on custom authentication schemes.
  • Implement role-based access control (RBAC) or claims-based authorization.
  • Validate tokens properly, checking expiration times and signature integrity.
  • Never expose sensitive operations via GET requests (e.g., /deleteUser?id=5).

Final Thoughts

Security isn’t an afterthought - it’s a fundamental part of software development. The mistakes listed here aren’t just theoretical; they’re responsible for real-world breaches that have cost companies millions. By taking the time to implement proper security practices, you’ll save yourself (and your users) from a lot of headaches. I have spent way too long trying to shoehorn security into legacy projects, it's not fun and you're never fully sure you covered everything. It's MUCH easier to include security from the start.

Stay safe, and secure your code before someone else exploits it.