mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
docs: rename benchmark metrics to standard security terms
Lead with the names a security engineer already knows instead of the coined ones: - catch rate -> recall (true-positive rate) - false-alarm rate -> false-positive rate (still reported as false alarms per 100 pushes) - proved-catch / proof rate -> exploit-verified findings (a working proof of concept) - precision stays precision (positive predictive value) The plain-English question for each metric stays as the explanation. Updated the valid-benchmark brief and the roadmap. No numbers changed. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
39a1873e5b
commit
3855945311
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Created 2026-10-12. This brief **supersedes the frozen-SZZ-pool evaluation** (`unseen-repo-evaluation`), which is retired.
|
Created 2026-10-12. This brief **supersedes the frozen-SZZ-pool evaluation** (`unseen-repo-evaluation`), which is retired.
|
||||||
SZZ guessed its labels and placed the vulnerability in the wrong location about half the time (audit: path 1/7,
|
SZZ guessed its labels and placed the vulnerability in the wrong location about half the time (audit: path 1/7,
|
||||||
output-encoding 1/8 sound). Also, ~76% of entries are library-internal (reachability not in-repo). Catch /
|
output-encoding 1/8 sound). Also, ~76% of entries are library-internal (reachability not in-repo). Recall and
|
||||||
false-alarm numbers from that pool are not valid benchmark results. This brief defines a benchmark with
|
false-alarm numbers from that pool are not valid benchmark results. This brief defines a benchmark with
|
||||||
sound ground truth and metrics that engineers and managers can understand.
|
sound ground truth and metrics that engineers and managers can understand.
|
||||||
|
|
||||||
@@ -41,15 +41,18 @@ tooling that found the SZZ pool's defects. Dozens of good cases are enough.
|
|||||||
|
|
||||||
## Metrics someone understands
|
## Metrics someone understands
|
||||||
|
|
||||||
|
These are the standard detector metrics. Each row leads with the name a security engineer already knows and
|
||||||
|
gives the plain-English question it answers.
|
||||||
|
|
||||||
| Metric | Plain-English question | Example |
|
| Metric | Plain-English question | Example |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **Catch rate** (recall) | Of real vulnerabilities, how many did it flag? | "Caught 18 of 20 (90%)" |
|
| **Recall** (true-positive rate) | Of real vulnerabilities, how many did it flag? | "Caught 18 of 20 (90%)" |
|
||||||
| **False-alarm rate** | On safe changes, how often does it cry wolf? | "Flagged 3 of 100 ordinary pushes" |
|
| **False-positive rate** | On safe changes, how often does it alarm? | "Flagged 3 of 100 ordinary pushes" |
|
||||||
| **Precision** | When it alarms, how often is it real? | "When it speaks up, it's right 8 of 10 times" |
|
| **Precision** (positive predictive value) | When it alarms, how often is it real? | "When it speaks up, it's right 8 of 10 times" |
|
||||||
| **Proof rate** | Of what it flags, how much can it *demonstrate*, not just suspect? | "12 of 18 catches came with a working demonstration" |
|
| **Exploit-verified rate** | Of what it flags, how much can it demonstrate with a working proof of concept, not just suspect? | "12 of 18 catches came with a working proof of concept" |
|
||||||
|
|
||||||
Report false alarms as **"per 100 pushes"**, which reflects a developer's experience. Vulnerabilities are rare
|
Report the false-positive rate as **false alarms per 100 pushes**, which reflects a developer's experience.
|
||||||
among real pushes. Precision depends on that ratio, so a 50/50 test set overstates it.
|
Vulnerabilities are rare among real pushes. Precision depends on that ratio, so a 50/50 test set overstates it.
|
||||||
|
|
||||||
Report the first two metrics together:
|
Report the first two metrics together:
|
||||||
|
|
||||||
@@ -58,20 +61,20 @@ Report the first two metrics together:
|
|||||||
|
|
||||||
This wording is easier for a manager to understand than "3/92, Wilson95 1.1–9.2%".
|
This wording is easier for a manager to understand than "3/92, Wilson95 1.1–9.2%".
|
||||||
|
|
||||||
## The gold-standard metric — and the project's edge
|
## The gold-standard metric, and the project's edge
|
||||||
|
|
||||||
**Proved catches** do not depend on labels. The search-with-proof / differential-exploit arm demonstrates the
|
**Exploit-verified findings** do not depend on labels. The search-with-proof / differential-exploit arm
|
||||||
bad effect on the vulnerable code and its absence on the fixed code. The demonstration *is* the ground truth.
|
demonstrates the bad effect on the vulnerable code and its absence on the fixed code. A working proof of concept
|
||||||
The headline to aim for is:
|
is the ground truth. The headline to aim for is:
|
||||||
|
|
||||||
> "On unseen app repos: caught and *proved* N of M real vulnerabilities, with K false alarms per 100 ordinary
|
> "On unseen app repos: caught and exploit-verified N of M real vulnerabilities, with K false alarms per 100
|
||||||
> pushes."
|
> ordinary pushes."
|
||||||
|
|
||||||
The architecture is built to produce this kind of benchmark.
|
The architecture is built to produce this kind of benchmark.
|
||||||
|
|
||||||
## Why the old approach was not feasible (recorded so it is not re-tried)
|
## Why the old approach was not feasible (recorded so it is not re-tried)
|
||||||
|
|
||||||
- SZZ ground truth is machine-guessed and ~half wrong → every catch/FP number off it is noise.
|
- SZZ ground truth is machine-guessed and ~half wrong → every recall or false-positive number off it is noise.
|
||||||
- Library-heavy corpus → most cases are unreachable in-repo, so a pre-push tool is scored on things it
|
- Library-heavy corpus → most cases are unreachable in-repo, so a pre-push tool is scored on things it
|
||||||
structurally cannot see.
|
structurally cannot see.
|
||||||
- Scoring regex-only (engine and LLM off) measured a tier nobody would ship alone.
|
- Scoring regex-only (engine and LLM off) measured a tier nobody would ship alone.
|
||||||
@@ -79,7 +82,7 @@ The architecture is built to produce this kind of benchmark.
|
|||||||
|
|
||||||
## Open questions for the spec phase
|
## Open questions for the spec phase
|
||||||
|
|
||||||
- How many verified positives are enough for a credible catch-rate interval (target set size)?
|
- How many verified positives are enough for a credible recall interval (target set size)?
|
||||||
- The negative:positive ratio that reflects real push traffic (for an honest false-alarms-per-100-pushes).
|
- The negative:positive ratio that reflects real push traffic (for an honest false-alarms-per-100-pushes).
|
||||||
- Curation workflow: how LLM adjudication + human spot-check are recorded and frozen per case.
|
- Curation workflow: how LLM adjudication + human spot-check are recorded and frozen per case.
|
||||||
- Language/framework coverage of the positive set (be explicit about what is and isn't represented).
|
- Language/framework coverage of the positive set (be explicit about what is and isn't represented).
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ The A/B experiments test whether the safety net works on repositories it has nev
|
|||||||
answer that question. Almost every push on an unseen repository is an ordinary change. Two numbers measure whether
|
answer that question. Almost every push on an unseen repository is an ordinary change. Two numbers measure whether
|
||||||
the safety net is useful, based on the hook's advisory output as a user sees it:
|
the safety net is useful, based on the hook's advisory output as a user sees it:
|
||||||
|
|
||||||
1. How often does it flag real vulnerability-introducing changes in unseen repositories (catch rate)?
|
1. How often does it flag real vulnerability-introducing changes in unseen repositories (recall)?
|
||||||
2. How often does it flag anything on ordinary changes in the same unseen repositories (false-alarm rate)?
|
2. How often does it flag anything on ordinary changes in the same unseen repositories (false-positive rate)?
|
||||||
|
|
||||||
Within-pair AUC on known fix pairs answers neither. It stays a development signal, not the goal.
|
Within-pair AUC on known fix pairs answers neither. It stays a development signal, not the goal.
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ machinery remains available. The engine/replay images are pinned. No catch/false
|
|||||||
Next, define and build the valid benchmark. Use sound, verified positives with in-repo reachability and ordinary
|
Next, define and build the valid benchmark. Use sound, verified positives with in-repo reachability and ordinary
|
||||||
negatives on unseen repos. Measure the whole tool with metrics an engineer understands. The design is in
|
negatives on unseen repos. Measure the whole tool with metrics an engineer understands. The design is in
|
||||||
`.kiro/specs/valid-detection-benchmark/brief.md`. Only once that benchmark exists does any detection number
|
`.kiro/specs/valid-detection-benchmark/brief.md`. Only once that benchmark exists does any detection number
|
||||||
(catch rate, false-alarms-per-100-pushes, proved-catch) mean anything. The kube `ax` lane is still the place the
|
(recall, false alarms per 100 pushes, exploit-verified findings) mean anything. The kube `ax` lane is still the place the
|
||||||
engine tier runs at scale, but it is infrastructure, not the gate.
|
engine tier runs at scale, but it is infrastructure, not the gate.
|
||||||
|
|
||||||
### Restoring the kube `ax` lane (for G1, operator-owned)
|
### Restoring the kube `ax` lane (for G1, operator-owned)
|
||||||
@@ -100,16 +100,17 @@ What remains before the G1 engine-arm replay:
|
|||||||
LLM adjudication and a human spot-check so the positives are sound, app-shaped and verified.
|
LLM adjudication and a human spot-check so the positives are sound, app-shaped and verified.
|
||||||
2. Ordinary negatives: everyday non-fix commits from the same application repos, a set much larger than the
|
2. Ordinary negatives: everyday non-fix commits from the same application repos, a set much larger than the
|
||||||
positives (false alarms discourage adoption).
|
positives (false alarms discourage adoption).
|
||||||
3. Measure the **whole tool** (all tiers on) on **unseen** repos, and report metrics an engineer reads: catch
|
3. Measure the **whole tool** (all tiers on) on **unseen** repos, and report metrics an engineer reads:
|
||||||
rate, **false-alarms per 100 pushes**, precision, and **proved-catch** (demonstrated, label-free). See the
|
**recall**, **false alarms per 100 pushes** (false-positive rate), **precision**, and **exploit-verified**
|
||||||
brief for the full definition and why the SZZ pool was not feasible.
|
findings (demonstrated with a working proof of concept, label-free). See the brief for the full definition
|
||||||
|
and why the SZZ pool was not feasible.
|
||||||
|
|
||||||
Exit: the benchmark exists (frozen, verified) and the whole tool has a first measured result on it.
|
Exit: the benchmark exists (frozen, verified) and the whole tool has a first measured result on it.
|
||||||
|
|
||||||
**G1. Score the arms on the valid benchmark**
|
**G1. Score the arms on the valid benchmark**
|
||||||
|
|
||||||
Quick rules, engine evidence, the LLM-guided arm, and their combination, each a registered decision rule,
|
Quick rules, engine evidence, the LLM-guided arm, and their combination, each a registered decision rule,
|
||||||
scored by catch rate at a fixed false-alarms-per-100-pushes budget, with proved-catch where available.
|
scored by recall at a fixed false-alarms-per-100-pushes budget, with exploit-verified findings where available.
|
||||||
|
|
||||||
Exit: one measured table of arms on unseen app-shaped code; keep only what generalises. (No number is quoted
|
Exit: one measured table of arms on unseen app-shaped code; keep only what generalises. (No number is quoted
|
||||||
until it comes from this benchmark, never the SZZ pool.)
|
until it comes from this benchmark, never the SZZ pool.)
|
||||||
@@ -138,7 +139,7 @@ against a realistic pre-push window (≤120 s target, 300 s hard):
|
|||||||
- **ENGINE-ON PILOT DONE (2026-10-12, clean host, 5 public repos), see brief "ENGINE-ON PILOT RESULTS".**
|
- **ENGINE-ON PILOT DONE (2026-10-12, clean host, 5 public repos), see brief "ENGINE-ON PILOT RESULTS".**
|
||||||
**regex 1/5, engine 0/5.** The engine added no catches over the regex floor. The budget hypothesis is
|
**regex 1/5, engine 0/5.** The engine added no catches over the regex floor. The budget hypothesis is
|
||||||
refuted: 3/5 repos finished their queue (deferred=0) and still emitted no finding, so change-scoping will not
|
refuted: 3/5 repos finished their queue (deferred=0) and still emitted no finding, so change-scoping will not
|
||||||
improve catch rate. The engine ranked the vuln region in all 5 and found the right sink on 2 (socketio deser,
|
improve recall. The engine ranked the vuln region in all 5 and found the right sink on 2 (socketio deser,
|
||||||
launch-editor, score 2.0), but withholds any finding it cannot anchor 1:1 to changed lines: all 5 hit
|
launch-editor, score 2.0), but withholds any finding it cannot anchor 1:1 to changed lines: all 5 hit
|
||||||
`ambiguous_line_correspondence` → `witness_unresolved` → `coverage_status=incomplete`, suppressing even the
|
`ambiguous_line_correspondence` → `witness_unresolved` → `coverage_status=incomplete`, suppressing even the
|
||||||
scored sinks. This is not a shallow-clone artifact. Detection does not meet release requirements.
|
scored sinks. This is not a shallow-clone artifact. Detection does not meet release requirements.
|
||||||
@@ -168,7 +169,7 @@ against a realistic pre-push window (≤120 s target, 300 s hard):
|
|||||||
|
|
||||||
- The pilot lowers the priority of change-scoped engine analysis again. Branch `engine-change-scoped-evidence-pass`
|
- The pilot lowers the priority of change-scoped engine analysis again. Branch `engine-change-scoped-evidence-pass`
|
||||||
(unmerged). Fitting the budget does not produce catches (3/5 pilot repos finished the queue with zero findings),
|
(unmerged). Fitting the budget does not produce catches (3/5 pilot repos finished the queue with zero findings),
|
||||||
so this is not required to improve catch rate. Keep only as a latency optimisation once detection works.
|
so this is not required to improve recall. Keep only as a latency optimisation once detection works.
|
||||||
- **Line-correspondence (merged c39fbb8).** `ambiguous_line_correspondence` fires on 5/5 realistic diffs, but the
|
- **Line-correspondence (merged c39fbb8).** `ambiguous_line_correspondence` fires on 5/5 realistic diffs, but the
|
||||||
pilot's corrected diagnosis shows it does not block detection here. The static tiers produce no vuln-family
|
pilot's corrected diagnosis shows it does not block detection here. The static tiers produce no vuln-family
|
||||||
findings to anchor. A region-level witness fallback only matters once #1/#2 yield findings.
|
findings to anchor. A region-level witness fallback only matters once #1/#2 yield findings.
|
||||||
|
|||||||
Reference in New Issue
Block a user