๐ Python Vulnerability Examples and Fixes
Use this page when: reviewing Flask, Django, FastAPI, worker processes, CLI helpers, internal automation, or data-handling code that looks harmless but sits on production trust boundaries.
How to read these examples
- Vulnerable snippet shows the unsafe habit.
- Safer pattern shows the direction you want in production code.
- Why it matters ties the defect to attacker value and business impact.
- Review cue is phrased so it can become a pull-request comment or checklist item.
Example 1 โ SQL injection with string formatting
Vulnerable snippet
username = request.args["username"]
query = f"SELECT id, role FROM users WHERE username = '{username}'"
row = conn.execute(query).fetchone()
Safer pattern
username = request.args["username"]
row = conn.execute(
"SELECT id, role FROM users WHERE username = ?",
(username,),
).fetchone()
Why it matters
- F-strings and
%formatting blur data and query structure, which is exactly what injection needs.
Business impact
- Account discovery, data leaks, auth bypass, and possible write/delete operations depending on DB permissions.
Review cue
- Parameterize values every time; never build SQL with f-strings,
%, or.format().
Example 2 โ Unsafe deserialization with pickle
Vulnerable snippet
payload = request.cookies.get("prefs")
settings = pickle.loads(base64.b64decode(payload))
Safer pattern
payload = request.cookies.get("prefs", "{}")
settings = json.loads(payload)
allowed = {"theme", "page_size"}
settings = {k: v for k, v in settings.items() if k in allowed}
Why it matters
pickle.loads()can reconstruct attacker-controlled objects and trigger arbitrary code execution paths.
Business impact
- Remote code execution in app or worker processes, secret theft, queue poisoning, and persistence opportunities.
Review cue
- Never deserialize untrusted bytes with pickle. Prefer JSON or another constrained format with explicit schemas.
Example 3 โ Path traversal in file retrieval
Vulnerable snippet
filename = request.args["name"]
with open(f"/srv/reports/{filename}", "rb") as fh:
return fh.read()
Safer pattern
from pathlib import Path
base = Path("/srv/reports").resolve()
name = request.args["name"]
path = (base / name).resolve()
if base not in path.parents and path != base:
raise PermissionError("invalid path")
with open(path, "rb") as fh:
return fh.read()
Why it matters
- User-controlled file names can escape the intended directory with
../tricks or platform-specific path variants.
Business impact
- Exposure of secrets, configuration, source code, SSH keys, tokens, or internal documents.
Review cue
- Resolve against a fixed base directory and prove the final path still lives inside it.
Example 4 โ SSRF through unrestricted URL fetch
Vulnerable snippet
url = request.json["url"]
r = requests.get(url, timeout=5)
return r.text
Safer pattern
from urllib.parse import urlparse
ALLOWED_HOSTS = {"status.example.com", "images.example-cdn.com"}
url = request.json["url"]
parsed = urlparse(url)
if parsed.scheme != "https" or parsed.hostname not in ALLOWED_HOSTS:
raise PermissionError("destination not allowed")
r = requests.get(url, timeout=5, allow_redirects=False)
return r.text
Why it matters
- Blind outbound fetch lets attackers pivot into metadata services, internal APIs, admin panels, or egress-trusted systems.
Business impact
- Credential theft, cloud compromise, internal reconnaissance, or abuse of third-party integrations.
Review cue
- Any user-influenced outbound request needs destination allowlists, redirect control, and private-address blocking.
Example 5 โ Command injection via subprocess shell=True
Vulnerable snippet
term = request.args["term"]
subprocess.run(f"grep -R {term} /srv/docs", shell=True, check=True)
Safer pattern
term = request.args["term"]
if not re.fullmatch(r"[a-zA-Z0-9._ -]{1,40}", term):
raise ValueError("bad search term")
subprocess.run(["grep", "-R", "--", term, "/srv/docs"], check=True)
Why it matters
- A shell interprets metacharacters, pipes, subshells, and injected options, which turns a search field into code execution.
Business impact
- Host compromise, secret exposure, tampering with logs or artifacts, and operational outage.
Review cue
- Prefer argument arrays over shells, validate inputs, and use
--when a tool may parse user data as flags.
Related pages
- Python / FastAPI / Django Security Review Guide
- SSRF, File Fetch, and Parser Abuse Review Guide
- Threat Modeling Methods and Workflows
Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.