IDOR - A medical records API checks who you are but never whose data you should access, so changing the patient_id in the URL lets any logged-in user read anyone's records.
Path Traversal - A file-download endpoint joins user-supplied filenames to a base directory without validation, letting attackers use ../ sequences to read files like /etc/passwd.
Missing Function-Level Access - Admin endpoints use @login_required but never check the user's role, so any authenticated user can delete accounts or export all data.
Debug Mode - A Django app deployed with DEBUG=True exposes full stack traces, the secret key, database credentials, and every URL route on any error page.
Missing Security Headers - API responses lack headers like Strict-Transport-Security and Content-Security-Policy, leaving browsers with no defense against clickjacking, XSS, or protocol downgrades.
Docker Compose Exposure - Mapping 5432:5432 silently binds PostgreSQL to all network interfaces with default credentials, exposing the database directly to the internet. See ufw on Docker docs
Unpinned Dependencies - A requirements.txt without version pins means every install can pull different - or compromised - package versions with no audit trail. E.g. LiteLLM fiasco, and see my article for actions to take.
Known Vulnerabilities - The app ships outdated packages with publicly disclosed CVEs that attackers actively scan for and exploit.
Weak Hashing - Passwords hashed with MD5 or plain SHA-256 can be cracked at billions of guesses per second on consumer hardware.
Hardcoded Keys - Encryption keys embedded in source code are present in every Git clone, laptop backup, and decompiled build, so a single source leak compromises all encrypted data.
SQL Injection - User input concatenated into SQL via f-strings lets attackers execute arbitrary queries like ' OR '1'='1 to dump or modify the entire database.
XSS - User content rendered with Markup() or |safe without escaping lets attackers inject JavaScript that steals session cookies.
NoSQL Injection - Raw JSON passed directly as a MongoDB query lets attackers inject operators like {"$ne": ""} to bypass authentication.
No Rate Limiting - The login endpoint allows unlimited attempts, making brute-force trivial - a 6-digit 2FA code is crackable in ~17 minutes at 1,000 req/s.
Client-Side Enforcement - Security rules like discount limits and transfer caps live only in frontend JavaScript, trivially bypassed with curl or Burp Suite.
Weak Password Policy - Registration accepts any password - including "password" and "1" - because Django's AUTH_PASSWORD_VALIDATORS is empty.
Insecure Password Reset - Reset tokens are generated from predictable values (MD5 of timestamp), never expire, aren't invalidated after use, and are returned in the API response.
Mass Assignment - A DRF serializer with fields = "__all__" lets users set sensitive fields like is_approved or seller_id by simply including them in the request body.
Untrusted CDN - JavaScript loaded from third-party CDNs without Subresource Integrity hashes means a compromised CDN can inject malicious code into every page load.
No Auth Logging - Login attempts, password changes, and failed authentications aren't logged at all, so credential-stuffing attacks go completely undetected.
No Alerting - Security events are logged but never monitored, so spikes in failed logins or admin access from unusual IPs happen silently.
Verbose Errors - Exception handlers return full stack traces, database connection strings, and internal file paths in HTTP responses, giving attackers a blueprint of the system.
Transaction Rollback - A financial transfer debits and credits in separate commits, so if the credit fails after the debit succeeds, the money simply vanishes.