Advanced

Getting the AI to find the security problems, not just the obvious ones

Most code review misses the scary problems -- the ones that don't crash your app, they just quietly hand over access. A general 'review this' asks the AI to look everywhere at once. It's far more effective to point it straight at security and ask for trouble.

What you will see

Running security pass Scanning 6 lines of code Line 1: sql_injection -> conn.execute('SELECT * FROM us Line 2: hardcoded_secret -> password = "hunter2" Line 4: hardcoded_secret -> api_key = "sk-live-abc123" Line 6: unvalidated_input -> print(user_input)

The full result is shown at the end of the exercise below.

About 3 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Run a dedicated security pass over the code

1

Collect a few code samples with the three big problems: SQL injection, hardcoded secrets, and unvalidated input.

code_samples = [ "conn.execute('SELECT * FROM users WHERE id = ' + user_id)", "password = " + chr(34) + "hunter2" + chr(34), "db.execute('INSERT INTO t VALUES ('" + chr(34) + "admin" + chr(34) + ")')", "api_key = " + chr(34) + "sk-live-abc123" + chr(34), "cursor.execute('SELECT * FROM t WHERE n = %s', [safe_value])", "print(user_input)", ]

Before you run it, say out loud what it will print. Then open the answer.

What it prints
code_samples = [ "conn.execute('SELECT * FROM users WHERE id = ' + user_id)", "password = " + chr(34) + "hunter2" + chr(34), "db.execute('INSERT INTO t VALUES ('" + chr(34) + "admin" + chr(34) + ")')", "api_key = " + chr(34) + "sk-live-abc123" + chr(34), "cursor.execute('SELECT * FROM t WHERE n = %s', [safe_value])", "print(user_input)", ]
Run a focused security pass rather than a general review, so these three problems stand out.
2

Flag each issue and count them.

issues = [] for i, line in enumerate(code_samples, 1): if "execute" in line and "+" in line and "%s" not in line: issues.append((i, "sql_injection", line[:30])) if "password" in line or "api_key" in line: issues.append((i, "hardcoded_secret", line[:30])) if "print" in line: issues.append((i, "unvalidated_input", line[:30])) print("Running security pass") print("Scanning %d lines of code" % len(code_samples)) for n, kind, line in issues: print("Line %d: %s -> %s" % (n, kind, line)) print("Total issues found: %d" % len(issues))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Running security pass Scanning 6 lines of code Line 1: sql_injection -> conn.execute('SELECT * FROM us Line 2: hardcoded_secret -> password = "hunter2" Line 4: hardcoded_secret -> api_key = "sk-live-abc123" Line 6: unvalidated_input -> print(user_input) Total issues found: 4
Read each finding, then fix the risky ones before shipping.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Point the AI at security, collect every finding, fix the risky ones with safe patterns, then verify.
1 Ask for a security-focused review
↓
2 Collect every finding into a list
↓
3 Fix the risky ones with safe patterns
↓
4 Re-check the fixes
Why this works
The usual suspects

Three problems dominate: SQL injection through built-up queries, secrets written straight into the code, and input that's used without validation. Ask the AI to run a security pass rather than folding it into a general review, and you'll catch these more often.

How to ask for the security pass

Say something specific like "review this only for security issues." A narrow ask gives a narrow, deeper result, while a general review scatters its attention. Read each finding, then fix the risky ones before shipping.

Examples

Turning string building into a real vulnerability

You: "Find security bugs in this query."
AI: "SQL injection. You build this query by adding strings together. Use a parameterized query instead."

query = "SELECT * FROM users WHERE name = '" + name + "'"

That line looks normal, which is the problem. If name comes from a login form, someone can type Robert'; DROP TABLE users; -- in place of their username and the database runs it verbatim. A parameterized query treats the input as data the whole time, so it can't become SQL. This is the kind of thing that only shows up when you ask specifically about security.

The secret hiding in plain sight

You: "Find any secrets exposed in this file."
AI: "You have a database password written in plain text. Move it out of the code."

DB_PASSWORD = "supersecret123"   # gets committed, gets shared, leaks

This one feels harmless. It's right there in the source, and the moment the code goes into a repository -- personal, team, or public -- the password is exposed to everyone who can see it. The fix is simple: move it to an environment variable or a config file that never gets committed, and the AI will usually catch these quickly.

Remembering that input is never trustworthy

You: "Is this form input safe to use?"
AI: "No. Nothing from a user should be trusted as-is. Validate it first."

age = request.form["age"]   # raw, untrusted, could be anything

The person filling out the form could type a number, a word, or a script. Treating that input as safe is how bugs turn into attacks. A focused security pass asks the AI to hunt for exactly this kind of spot -- anywhere data arrives from outside the program -- and validate it before it's used.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Your first full review
Previous Lesson
Your first full review
Next Lesson
Finding the slow parts instead of guessing
Finding the slow parts instead of guessing →