A small set of weakness types accounts for most real vulnerabilities, and AI tools reproduce them reliably because insecure examples are everywhere in their training data. Learn to recognize the common ones on sight.
Watch
A guide to the OWASP Top 10 web application risks, from a security vendor's channel. It covers the kind of weaknesses this lesson asks you to look for.
Two catalogs to know
- CWE (Common Weakness Enumeration) names categories of software weakness. MITRE publishes a yearly CWE Top 25 of the most dangerous ones, a useful target list.
- OWASP Top 10 ranks the most critical web application security risks. The OWASP Cheat Sheet Series gives concrete prevention advice for each.
Weaknesses to recognize, with fixes
Injection (SQL, command, template)
Untrusted data is pasted into an interpreter's input.
# Vulnerable: shell interprets the filename
subprocess.run(f"convert {filename} out.png", shell=True)
# Safer: no shell, arguments passed as a list
subprocess.run(["convert", filename, "out.png"], check=True)
For SQL, always use parameterized queries (see lesson 2).
Path traversal
User input controls a file path, so ../../etc/passwd escapes the intended folder.
from pathlib import Path
BASE = Path("/srv/uploads").resolve()
def safe_path(name: str) -> Path:
p = (BASE / name).resolve()
if not p.is_relative_to(BASE):
raise ValueError("invalid path")
return p
Cross-site scripting (XSS)
User input is written into a web page without escaping. Use the framework's automatic escaping, avoid raw HTML insertion, and apply a content security policy.
Weak randomness and cryptography
Generated code often uses a general-purpose random generator for tokens, or invents its own encryption.
import random, secrets
token = random.random() # Not for security: predictable
token = secrets.token_urlsafe(32) # Cryptographically secure
Never write your own cryptography. Use well-reviewed libraries with safe defaults, and store passwords with a dedicated password-hashing algorithm via a vetted library, not a fast general hash.
Hard-coded secrets
API keys and passwords in source or example files. Load secrets from the environment or a secrets manager, and scan for them (lesson 5).
Broken access control
The code verifies who you are but not what you may do. For every endpoint that takes an object ID, check that the caller is allowed to access that object. This is one of the most common serious flaws and one of the hardest for tools to see, because it depends on your rules.
Unsafe deserialization and parsing
Loading untrusted data with formats that can execute code, or parsing XML with external entities enabled. Use safe parsers and data-only formats for untrusted input.
Server-side request forgery (SSRF)
The server fetches a URL supplied by a user, which can be pointed at internal services. Validate and allow-list destinations.
Insecure defaults
Debug mode left on, permissive CORS, disabled certificate verification ("to make the error go away"), overly broad IAM permissions or open storage buckets. Treat any line that disables a safety check as a red flag.
Error handling and information leaks
Stack traces and internal details returned to users, or errors swallowed so failures go unnoticed.
How the model's habits create these
- It imitates the most common pattern, which is often the quick pattern.
- It optimizes for code that runs, not code that is safe against hostile input.
- It lacks your threat model and business rules unless you tell it.
- It follows the style of surrounding code, so one vulnerable function can seed more.
Prompting for safer code
Helpful, but never sufficient on its own:
- State requirements: "validate input, use parameterized queries, no shell, least privilege".
- Provide the threat model and relevant project security rules in your instruction file.
- Ask for a second pass where the model reviews its own output against a named checklist, then verify with real tools.
Telling a model to write secure code reduces risk but guarantees nothing. Your protection comes from review, automated analysis and tests.
Resources
The current yearly ranking, with links to each weakness.
The standard awareness list for web application security risks.
Look up the cheat sheet for each weakness above.
A Python security linter. Browse its list of checks to see common unsafe patterns.
If your product also embeds an LLM, these risks apply in addition to the above.
Check yourself
- Ask an AI tool to write a file upload endpoint, a login handler and a search endpoint. Review each against the list above.
- For every issue, write the unit test that would fail on the vulnerable version.
- Add the top three issues you found to your project's instruction file as explicit rules.