• Stealth Security
  • Posts
  • 10 Signs Your Code Is Vulnerable (And How to Protect Against It)

10 Signs Your Code Is Vulnerable (And How to Protect Against It)

If you want secure code, you must first know what bad code looks like.

Writing code is easy. Writing secure code is hard.

The truth is, most developers don’t realize their code is vulnerable until something breaks. Or, worse, until someone attacks it.

In this tutorial, we’ll see 10 clear signs that your code might be vulnerable to attacks. And more importantly, how to fix it.

1. Hardcoded Credentials

This one is everywhere. Maybe you’ve seen it yourself — an API key sitting right there in the code. A database password written in plain text.

It looks like this:

DB_PASSWORD = "supersecret123"
API_KEY = "sk_test_abc123"

If this code leaks (and it will), attackers can do whatever they want. They can log into your systems, steal your data, or run up huge bills on cloud services — all without breaking a sweat.

And here’s the scary part: this kind of leak doesn’t just happen when your whole project gets hacked. It can happen when someone pushes code to GitHub and forgets to add .env to .gitignore. Boom — your secret keys are now public.

How to protect against it

Never hardcode sensitive data like API keys, database passwords, or tokens. Instead:

  • Use environment variables. These are hidden from the source code and can be safely managed per environment (dev, test, production).

  • Use a secure vault, like HashiCorp Vault, AWS Secrets Manager, or even a .env file (with proper access control).

  • Keep secrets out of version control. Always use .gitignore to exclude config files that hold secrets.

Run a secret scanner (like GitLeaks or TruffleHog) before every push. These tools can catch sensitive info before it leaks.

2. No Input Validation

If you trust user input, you’re already in trouble. Attackers love sending weird stuff — super long strings, funky characters, or unexpected formats.

Here’s what it looks like:

username = request.GET['username']
print("Hello " + username)

Now someone enters:

username=Robert'); DROP TABLE users; --

Boom. You’ve just been SQL injected. Your database table? Gone.

Without validation, your app can break or even be hijacked. Bad input can lead to issues like SQL injection, cross-site scripting (XSS), and general bugs.

Basically, you’re giving attackers a blank check.

How to Protect Against It

  • Validate everything. If it’s supposed to be an email, check the format. If it’s a number, make sure it’s a number.

  • Use strict data types. Don’t just assume input is clean. Make it pass a test.

  • Limit input length. No one needs a 5,000-character username.

  • Escape special characters. Especially if you’re using input in HTML or SQL.

  • Use parameterized queries. Never build SQL strings from raw user input.

3. Poor Error Handling

This is what lazy error handling looks like:

except Exception as e:
    print(e)

Or worse:

except:
    pass

Silent errors are dangerous. And showing full error messages to users? That’s handing over a map to your system.

Imagine a database error pops up in production, and your app spits out something like:

psycopg2.OperationalError: could not connect to server: Connection refused

Great — now attackers know what database you’re using, and they might start poking around.

How to Protect Against It

  • Log detailed errors — but do it securely. Use logging tools or services, and don’t store logs where users can see them.

  • Show users simple messages like:
    "Oops! Something went wrong. Please try again later."
    That’s all they need to know.

  • Never expose stack traces in production. Turn off debug mode and use proper error pages.

  • Handle specific exceptions where possible, so you know exactly what failed and why.

Example:

try:
    process_data()
except ValueError as e:
    logger.error(f"Data error: {e}")
    return "Invalid input. Please check your data."
except Exception as e:
    logger.exception("Unexpected error")
    return "Something went wrong. Try again later."

Use error monitoring tools like Sentry, Rollbar, or LogRocket. They catch errors, track them, and help you fix them — before users even notice.

4. Outdated Dependencies

Using old packages is like leaving your front door wide open. Attackers know exactly where the weak spots are — and they actively scan for them.

If your package.json or requirements.txt file hasn’t changed in years, that’s a red flag.

How to Protect Against It

  • Update regularly. New versions often patch security flaws.

  • Audit your dependencies. Use tools like npm audit and pip-audit based on your codebase.

  • Automate updates with tools like Dependabot, Renovate, or PyUp.

Even small packages can have big impacts. Stay updated, stay safe.

5. No Authentication or Weak Authentication

If your app lets anyone in without verifying who they are — that’s game over. Weak logins are just as dangerous.

Common mistakes include

  • No password complexity rules

  • Storing passwords in plain text

  • No account lockout after repeated failed logins

How to Fix It

  • Hash passwords using strong algorithms like bcrypt

  • Enforce strong password policies (min length, symbols, etc.)

  • Use Multi-Factor Authentication (MFA) for extra protection

Example in Python:

import bcrypt
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())

A few extra lines of code can stop a full-blown breach.

6. Missing Authorisation Checks

Authentication checks who you are. Authorization checks what you can do. Skipping the second one is like giving everyone admin access.

Example Mistake

@app.route('/user/<id>')
def get_user(id):
    return User.query.get(id)

No check to see if the current user is allowed to view that data.

How to Fix It

  • Always verify ownership and roles before showing or modifying data.

  • Implement access control rules across your API and frontend.

  • Don’t trust IDs from the frontend — verify on the backend too.

7. Exposed Sensitive Data in URLs

Ever seen a password reset link like this?

https://example.com/reset-password?token=abcd1234

Looks harmless — but it’s not. Tokens, session IDs, and API keys should never be in URLs. They get saved in:

  • Browser history

  • Server logs

  • Analytics tools

How to Fix It

  • Use HTTP headers or POST requests to send sensitive data

  • Avoid GET-based auth actions — stick with secure alternatives

8. No Rate Limiting

Without rate limits, attackers can hit your server with:

  • Brute-force login attempts

  • Form spam

  • Denial of Service (DoS) attacks

How to Fix It

Set a max request limit per IP or user. Use tools like:

from flask_limiter import Limiter
limiter = Limiter(app, key_func=get_remote_address)

Or configure NGINX with built-in rate limiting. Stop abuse before it starts.

9. Unsafe File Uploads

Letting users upload files? Cool. But if you’re not careful, they can:

  • Upload malware

  • Overwrite key files

  • Execute scripts on your server

Example Mistake

file. Save(f"/uploads/{file.filename}")

That filename could be anything — even "../../../etc/passwd".

How to Fix It

  • Check file types (not just extensions — inspect content)

  • Rename files before saving

  • Store files outside your web root

  • Limit file sizes to prevent denial of storage attacks

10. Missing HTTPS

If your app still uses plain old HTTP, all data travels in the open — including:

  • Passwords

  • Tokens

  • Personal info

Attackers can sniff it all with tools like Wireshark.

How to Fix It

  • Use HTTPS everywhere

  • Get a free SSL cert from Let’s Encrypt

  • In Flask, redirect insecure traffic:

@app.before_request
def before_request():
    if not request.is_secure:
        return redirect(request.url.replace("http://", "https://"))

Encrypting traffic is not optional — it’s table stakes for modern apps.

Final Thoughts

Writing secure code isn’t about being perfect. It’s about being careful. Slow down. Look at your code with fresh eyes. Think like an attacker. Plan for failure before it happens.

The best security isn’t patched in later — it’s baked in from the start.

New to cybersecurity? Check out our Security Starter Course.

Reply

or to participate.