Skip to main content

The Security Audit Mindset

intermediate15 min readLesson 104 of 169

Deserialization, shell injection, and secrets โ€” find them, then fix them.

Security for intermediates is a habit of mistrusting inputs and defaults. Three bugs cover most of what you'll meet:

1. Unsafe deserialization

# NEVER on data from users/network:
import pickle
obj = pickle.loads(blob)          # executing attacker-chosen code

# YES for untrusted data:
import json
obj = json.loads(text)            # data only, no code execution

2. Shell injection

# NEVER:
import subprocess
subprocess.run(f"convert {filename}.png", shell=True)   # filename='x; rm -rf ~'

# YES:
import shlex, subprocess
subprocess.run(["convert", f"{filename}.png"])          # argv list, no shell

The list form never lets metacharacters through; shlex.quote()/shlex.join() are for the rare case you truly need a shell string.

3. Secrets and paths

Secrets come from environment variables (os.environ["API_KEY"]), never hard-coded and never logged. User-supplied paths go through the safe_join discipline from module 6 (resolve + containment check).

Audit method

Read code asking one question: what input can reach this line, and what is the worst thing it can do there? The practice set gives you vulnerable functions to repair โ€” the same exercise security reviewers run on real PRs.

Now practice

Security Audit DrillsRepair vulnerable functions โ€” the PR-review workout.3 challenges ยท ยท ~30 min