Step 322. Second CVE: Independent Analysis — Standing Alone Through the Analysis Cycle
Level 4 — Reporting, CVE Analysis & Open-Source Contribution | Difficulty ★★★★☆ | Estimated time: 3 hours
Prerequisites: you’ve completed the full cycle of Steps 320–321 once (selection → diff analysis → notes → reproduction → report).
- What you need: Git Bash and Python, the deliverables of Steps 320–321 (practice repository, analysis notes, PoC, report), and a timer to track your time.
- Caution: ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime. Again today, every experiment happens only inside the local repository you created yourself.
Steps 320–321 were guided analysis, with the book leading the way. Today the guidance comes off. The goal is to run the full cycle — "selection → obtain the patch → diff analysis → lab setup → reproduction → report" — on your own, and faster than last time. At the end you’ll go one step further with the question "is this patch complete?" — a measured attempt at bypassing the patch with mutated inputs, the researcher’s final verification. Once this cycle is in your body, you’ll be the researcher who understands each new vulnerability before anyone else.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Perform the full 1-day analysis cycle alone, guided only by a checklist
- Select a CVE (or practice target) to analyze by the criteria "patch public / reproducible / a language I read"
- Measure the time from selection to reproduction and compare it against your first analysis
- Verify a patch’s completeness (bypassability) with mutated inputs
- Decide your own fallback points when stuck (advisory → commit message → diff → notes)
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | Git Bash + Python 3.10+ (standard library only) |
| Today’s tools | The independent-analysis checklist, a time-tracking table, a mutation-input list |
| Concepts needed | Step 320’s four-section analysis notes, Step 321’s reproduction contrast structure, patch bypass |
| Today’s deliverable | A second analysis report + time records + a patch-completeness verification result |
2-1. What Independent Analysis Is — What’s Missing Is the Answer Key
The difference between your first and second analysis is not the target but whether an answer key exists. Last time the book guided you: "read this diff this way." Starting today, you are the guide.
The real goal of independent analysis is not speed but resilience when stuck. Real CVE analysis starts with no analysis posts at all. Getting stuck is not failure but the normal state — and that’s exactly why it’s valuable.
2-2. The Independent-Analysis Checklist — The Skeleton of the Cycle
Here’s a seven-box checklist that compresses Steps 320–321 into something you can follow alone. It’s today’s work procedure and the template for every analysis going forward.
[ ] 1. Selection — is the fix commit public, can I build a reproduction environment, is it a language I read?
[ ] 2. Obtain — do I have the code of both versions, vulnerable and patched? (git log / git show)
[ ] 3. Diff — did I answer the three questions (what disappeared / what arrived / what happens without it)?
[ ] 4. Notes — did I fill the four sections: type (CWE) / trigger / impact / patch principle?
[ ] 5. Reproduction — did I confirm both: success on the vulnerable version + blocked on the patched version?
[ ] 6. Report — did I complete the five sections: overview/root cause/impact/reproduction/fix?
[ ] 7. Completeness — did I try to bypass the patch with mutated inputs?
2-3. Fallback Points When Stuck — The Chain of Clues
Real CVEs are not friendly. When the diff is huge or the codebase is unfamiliar, climb back up this chain.
stuck → read the official advisory → clues in the commit message
→ narrow the diff by security patterns (validation/escaping/length checks)
→ trace the call paths of the found function → trigger hypothesis → verify in the lab
The advisory and the commit message are your minimum clues. Starting from them and reading the code is itself this Step’s goal — what matters is not finding the answer but walking the finding procedure alone.
2-4. Patch Bypass — "Is This Patch Complete?"
Even when a patch blocks the original attack, whether it also blocks mutated inputs is a separate question. Patches that block one quote but fall to uppercase mutations or encoding bypasses are genuinely common. Discovering a bypass is itself a new vulnerability — the point where the reporting flow of Steps 318–319 begins.
Today you’ll throw three mutated inputs at Step 320’s patched version and measure whether the patch is truly complete.
3. Follow Along
Today’s practice target is one more vulnerability — rather than building a brand-new "third vulnerability" that wasn’t in the Step 320 practice repository, you’ll instead work against the search.py patch you built yourself in the Step 320 mission, focusing today on "the procedure for walking the cycle alone" and "verifying patch completeness." The procedure is identical when you do this against a real CVE.
3-1. Start the Timer and Select
First, record your start time. Measuring elapsed time is today’s core data.
Analysis start: 2026-09-09 __:__
Target: (the search.py patch from the Step 320 mission / or a real CVE number)
Selection basis: fix commit exists / reproduction environment available / a language I can read
How to read it: you check these same three conditions first when picking a real CVE. Without a fix commit, diff analysis is impossible; without a reproduction environment, proof is impossible; with a language you can’t read, the analysis drifts. A target that passes all three is "today’s exam paper."
3-2. Checklist 1–4 — Walking Obtain, Diff, and Notes Alone
Proceed with only the 2-2 checklist in view, without the book’s guidance. You already know the commands.
cd oneday-lab
git log --oneline # confirm the vulnerable/patched commit hashes
git diff <vuln-hash> <patch-hash> # the patch diff
Read the diff and write your analysis notes. This time, fill the four sections alone without looking at the book’s examples — type, trigger, impact, patch principle.
The trick to working alone: when stuck, fall back along the 2-3 chain. "What’s the core change in this diff?" → start from the three questions (what disappeared / what arrived / what happens without it). These three questions are yours now, book or no book.
3-3. Checklist 5–6 — Reproduction and Report
Re-run the search-feature PoC you built in the Step 321 mission and confirm the contrast.
git show <vuln-hash>:search.py > search_v1.py
git show <patch-hash>:search.py > search_v2.py
python search_poc.py search_v1.py
python search_poc.py search_v2.py
If the result is "vulnerable version succeeds / patched version blocks," write the report. That completes the review cycle of Steps 320–321. Record the time.
Reproduction complete: 2026-09-09 __:__ (___ hours ___ minutes since start)
Why measure: the time difference between your first and second analysis is the yardstick of growth. With split records like "selection 30 min + diff analysis 1 h + reproduction 40 min," you can also see which stage is slow.
3-4. Checklist 7 — Verifying Patch Completeness (Measured)
Now for today’s new step. The patch blocked the original attack. But does it block mutations too? Throw three injection mutations at Step 320’s patched version (app_v2.py).
Input (Git Bash):
python -c "
import importlib.util
spec = importlib.util.spec_from_file_location('t', 'app_v2.py')
app = importlib.util.module_from_spec(spec); spec.loader.exec_module(app)
conn = app.init_db()
for payload in ["admin' --", "admin' OR '1'='1' --", "' OR 1=1 --"]:
ok = app.login(conn, payload, 'x')
print(f' payload={payload!r} ->', 'VULNERABLE' if ok else 'blocked')
"
Output (measured 2026-09-09):
[FAIL] login failed
payload="admin' --" -> blocked
[FAIL] login failed
payload="admin' OR '1'='1' --" -> blocked
[FAIL] login failed
payload="' OR 1=1 --" -> blocked
How to read it: all three mutations were blocked. This patch is complete. Binding doesn’t filter specific payloads — it closes the very channel through which input could become syntax — so there’s no room for mutation.
Why do this: the opposite result — a mutation getting through — is exactly the discovery of a "patch-bypass vulnerability." When building a verification list, expand in this order: ① the original attack, ② mutations with changed conditions (different field, case changes, encoding), ③ similar paths (other functions using the same input). Today’s target has no structural bypass, but had this patch blocked input via a string blacklist, these three attempts would have caught a new vulnerability.
3-5. Completing and Publishing the Report
The second report adds two lines the first one didn’t have.
[Analysis process log]
- Time spent: selection __min + obtaining __min + diff analysis __min + reproduction __min + report __min = total __hours
- Compared to the first analysis: (stages that got faster / stages still slow)
[Patch completeness verification]
- Mutations tried: admin' -- / admin' OR '1'='1' -- / ' OR 1=1 --
- Result: all blocked — patch complete (no bypass)
(In an actual report, each [section] becomes a Markdown subheading.)
Publish only after passing Step 321’s 3-6 checklist. That makes two cumulative analysis reports.
3-6. What Changes with a Real CVE (Screen Example)
The difference between the practice repository and a real CVE comes down to just three things.
- Selection — pick one with a "fix commit" link from GitHub Security Advisories, the NVD, or vendor release notes (screen example — verify in an internet-connected environment).
- Obtaining — after
git clone,git diffbetween the two tags/commits named in the advisory. For large repositories, the Files changed tab on the commit page is faster. - Reproduction environment — instead of today’s file extraction, you need a VM or Docker image with the vulnerable version installed. Write the vulnerable-version installation steps into a
Dockerfileand it gets reused in your next analysis.
The procedure — three questions, four-section notes, contrast reproduction, five-section report, completeness verification — is not one bit different from what you practiced today.
4. Missions & Exercises
Mission — A Fully Independent Analysis of a Fourth Vulnerability
- Design a new vulnerability in
oneday-labyourself — for example, aprofile.pywhose profile-file reading feature allows path traversal (../../etc/passwd-style). Create it as a vulnerable commit followed by a patch commit - Cover up the "design intent" memo you wrote while building it, and analyze it using only the 2-2 checklist — as if it were someone else’s code
- Record the time spent per stage from selection to reproduction
- Complete the five-section report + the process log + the patch-completeness verification (including path-traversal mutation attempts)
- After passing Step 321’s 3-6 checklist, publish (or save as a publish-ready file) — three reports cumulative
Exercises
Exercise 1. State the three conditions for CVE selection in independent analysis, and explain what problems arise if you pick "a CVE whose fix commit isn’t public."
Exercise 2. Recite the fallback chain (2-3) in order for when you’re stuck in front of a huge diff.
Exercise 3. Explain the difference between "the patch blocked the original attack" and "the patch is complete," connecting it to today’s measured mutation-input experiment.
Exercise 4. What does recording time per stage tell you? And how do you use that data in your next analysis?
5. Model Answers & Completion Criteria
Mission Model Answer
Here’s the skeleton of the path-traversal example. Vulnerable version:
def read_profile(name):
with open(f"profiles/{name}.txt", encoding="utf-8") as f:
return f.read()
Patched version (validation-added pattern):
import os
def read_profile(name):
base = os.path.realpath("profiles")
target = os.path.realpath(os.path.join(base, f"{name}.txt"))
if not target.startswith(base + os.sep):
raise ValueError("path not allowed")
with open(target, encoding="utf-8") as f:
return f.read()
Analysis-notes example: type CWE-22 (Path Traversal) / trigger ../ in name / impact arbitrary file read on the server / patch principle — normalize the path, then block access outside the base folder. Completeness-verification mutation examples: ../, .... (Windows), the double-bypass ....//, URL encoding %2e%2e%2f, etc.
How to verify: ① did you pinpoint the vulnerable spot from the diff alone, without reading the design memo? ② did the vulnerable/patched contrast reproduction succeed? ③ did you build and try a mutation-input list? ④ was time recorded per stage? ⑤ does the report have the five sections + process log + completeness section?
Exercise Answers
Answer 1. The three conditions are: ① is the fix commit (or before/after versions) public, ② can you build a reproduction environment, ③ is it a language/platform you can read. A CVE with no public patch makes diff analysis itself impossible — there’s no map of "what was fixed," so you’re hunting a needle through the entire codebase, and without patch comparison as a control group, reproduction proof weakens.
Answer 2. When stuck: ① read the official advisory to narrow the affected component, ② look for security clues in the commit message (fix/security/CVE), ③ narrow the diff by security patterns (added validation/escaping/length checks), ④ trace the found function’s call paths back to build a trigger hypothesis, ⑤ verify in the lab. If any stage makes no progress, fall back one stage higher.
Answer 3. "Blocked the original attack" is a fact about one input; "complete" is a claim about the whole set of mutated inputs. In today’s measurement, all three mutations (admin' --, the ' OR '1'='1 family) were blocked, confirming the binding patch is complete. Conversely, had a mutation gotten through, that would be a patch bypass — a new vulnerability, leading to a report.
Answer 4. It tells you which stage is the bottleneck. For instance, if diff analysis got faster but environment setup is still slow, next time you can prepare a Dockerfile template in advance and automate the environment stage. Time records are a tool for improving your own cycle with data, not intuition.
Completion Criteria Checklist
- [ ] I can perform the full cycle using only the seven-box checklist from 2-2
- [ ] I can apply the three CVE-selection conditions (patch public / reproducible / my language)
- [ ] I can explain the fallback chain when stuck (advisory → commit message → patterns → call paths → verification)
- [ ] I recorded time per stage and compared it against my first analysis
- [ ] I verified patch completeness with mutated inputs
- [ ] I completed a second (or third) analysis report
6. Common Pitfalls & Fixes
Wall 1. I know the answer, so I can’t pretend to analyze
Symptom: since you built the vulnerability yourself, you know the answer before even reading the diff.
Cause: today’s training target is not "pretending not to know the vulnerability" but walking the procedure alone. Even knowing the answer, the hand motions of the three questions and the four-section notes remain.
Fix: cover the design memo and read the diff first. And real-world instincts ultimately come from real CVEs — once the checklist is in your body, pick a recent CVE with no analysis posts yet and apply the same procedure. That’s this chapter’s true graduation exam.
Wall 2. My hands freeze in front of a CVE with zero analysis posts
Symptom: you search and find no walkthrough, so you can’t find a starting point.
Cause: that’s normal. There are no analysis posts — which is exactly why it’s valuable.
Fix: go to the first link of the 2-3 chain — the official advisory and commit message are your minimum clues. Just knowing "which file was fixed" is a starting point. The process of growing your code-reading ability is itself this Step’s goal.
Wall 3. I got absorbed and forgot to track time
Symptom: after finishing the reproduction, you realize you never wrote down the start time.
Cause: immersion is a good thing. Only the data flew away.
Fix: Git already knows the times — git log --format="%h %ad %s" shows each commit’s timestamp, letting you restore rough per-stage times (a command you can verify yourself, measured 2026-09-09). From now on, build the habit of writing the start time next to the checklist’s first box.
Wall 4. A mutation got through, but I’m not sure
Symptom: a mutated input seems to succeed on the patched version, but you can’t tell if it’s a bug or your mistake.
Cause: every bypass discovery starts with "did I do something wrong?"
Fix: go back to the reproduction contrast structure — ① does the same mutation work on the vulnerable version (it should), ② is the original attack blocked on the patched version (it should be). If both are "yes" and only the mutation gets through on the patched version, that’s a real bypass. In the practice repository, suspect your design; with a real CVE, proceed to the reporting procedure of Steps 318–319.
Wall 5. Chasing speed made the analysis shallow
Symptom: you finished faster than the first analysis, but the report is sloppy.
Cause: this chapter’s goal is not speed but independence and resilience. A fast and shallow analysis is worse than copying a walkthrough.
Fix: check completion by sections, not by time — the notes’ four sections, the report’s five sections, the completeness verification. Only time measured after all of them are filled means anything.
7. Summary
Today’s Concepts
| Concept | One-line explanation |
|---|---|
| Independent analysis | Walking the full cycle alone, with no answer key |
| Selection’s 3 conditions | Patch public / reproducible / a language you can read |
| Fallback chain | Advisory → commit message → security patterns → call paths → lab verification |
| Patch bypass | An incomplete patch: original attack blocked, mutations get through |
| Completeness verification | Verification in the order: original attack → mutated inputs → similar paths |
| Time tracking | The habit of improving your own cycle with per-stage time data |
Today’s Commands & Formats
| Tool | What it does |
|---|---|
| Independent-analysis checklist | Selection → obtain → diff → notes → reproduction → report → completeness |
git log --format="%h %ad %s" |
Restore per-stage times from commit timestamps |
| Mutation-input list | Original attack → condition mutations → similar paths |
| Report + process log | Five sections + time spent + completeness verification results |
The Core Instinct
Today you gained a seven-box checklist. Those seven boxes are a universal procedure that rides onto any language, any CVE, any codebase. Someone who knows where to fall back when stuck goes farther than someone who never gets stuck.
And remember the last box — "is this patch complete?" When every mutation is blocked, as in today’s measurement, your confidence in the analysis deepens; when even one gets through, that’s your next new vulnerability. Where the analyst’s cycle becomes familiar, the discoverer’s cycle begins.
Once every box is checked, Step 322 is complete.