mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-18 04:29:27 +00:00
docs(specs): WordPress flaw classes, the corpus insight, and an IR brief
Three directions recorded, each grounded in what this session measured. **WordPress by flaw class, not by plugin** (tasks 5.8, 5.9). One plugin is a checkout; a class is a claim. WordPress's recurring shapes are narrow and each maps to a family that already exists -- unauthenticated wp_ajax_nopriv reaching $wpdb, a missing capability check, unescaped output, arbitrary file operations. Two of the four are blocked on gaps this session found: access control cannot be asked at all because PHP has no obligation facts (5.9), and unescaped output is blocked on the flat sanitizer list (5.6). The observable is a class-by-class table across several plugins saying found, missed, or out of scope -- a single found CVE is not the artifact worth teaching from. **Why a corpus of benchmarks is not enough on its own**, written into overview.md as the finding it is rather than an opinion. Twelve engine defects in one session against three real repositories, and the three gates stayed byte-identical through every fix. A gate that does not move is a corpus that could not see the bug. The reason is structural: a pair is a labelled function with a declared family and a known answer, so it cannot exercise which region to look at, what to spend, whether a capability is reachable, whether two entry points share a sink, whether the question fits in an argv slot, or whether a flow crosses a module. Three of the twelve were quiet failures where the tool reported clean and every honesty counter agreed -- which a benchmark score cannot express, because the score is computed from the verdicts that exist. The corpus is the holdout that stops per-repository tuning, and the wrong instrument for finding out whether the tool works. **ir-consolidation** (brief, unapproved) separates two questions the IR suggestion contains, which have opposite answers. The SOURCE IR is already carried rather than about to be added: semantic/ is 3218 lines, 16% of the codebase, measured at 2.2% entailment against the CPG's 41.3% and still running as a proposer -- and Vine and P-Code are binary IRs, so the work there is subtraction. The MISSING abstraction is C arithmetic, and there GhidraPAL's three-valued-logic abstract interpreter over Ghidra P-Code is exactly the right shape: "can this index exceed this allocation" is a value question, which is what a bit-level TVL domain answers and what every libpng overflow needs. Vine is dormant since 2009 and is not the candidate. The constraint is recorded as an ordering: question 1 lands before question 2 starts, or adopting an IR makes the growth problem worse. And the cost that matters is not lines but the number of things that can silently return nothing -- this session found three such in a single PHP scan, and a binary pipeline adds a build, a lifter and a domain, each able to produce an empty result that looks like a clean one. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
co-authored by
Claude Opus 5
parent
8579c10e7c
commit
db273dde53
@@ -71,6 +71,44 @@ invocation per query kind.
|
||||
controlling control structure, so every guard question runs on CFG dominance instead.
|
||||
- **`execution_confirmed` has no production caller.** The rung exists and nothing reaches it.
|
||||
|
||||
## Why a corpus of benchmarks is not enough on its own
|
||||
|
||||
This is the finding worth teaching, and it is not an opinion — it is what the gates say.
|
||||
|
||||
**Twelve engine defects were found in one session by pointing the tool at three real repositories. The three
|
||||
gates stayed byte-identical through every single fix.** A gate that does not move is a corpus that could not
|
||||
see the bug.
|
||||
|
||||
| defect | what the corpus saw |
|
||||
|---|---|
|
||||
| `resolve` matched inside `resolveUrl` (sanitizers) | nothing |
|
||||
| `user` matched inside `users` (dischargers) | nothing |
|
||||
| `gets` matched inside `fgets` (sinks) — 26 identical false positives | nothing |
|
||||
| the model layer had zero production callers | nothing |
|
||||
| `query_batch` implemented, tested, unreachable | nothing |
|
||||
| a paid budget halting unpaid arbitration | nothing |
|
||||
| a region with no function claiming the whole repository's answer | nothing |
|
||||
| a guard discharging an obligation it is not a guard of | nothing |
|
||||
| `joern-parse` failing where the frontend succeeds | nothing |
|
||||
| a 1.49MB batch over Linux's 128KB argv cap | nothing |
|
||||
| an array callable not recognised as a handler | nothing |
|
||||
| one defect reported as twenty-six findings | nothing |
|
||||
|
||||
The reason is structural rather than a gap in the corpus's coverage. **A pair is a labelled function with a
|
||||
declared family and a known answer.** It cannot exercise: which region to look at, what to spend, whether the
|
||||
capability is even reachable, whether two entry points share a sink, whether the question fits in an argv
|
||||
slot, or whether a flow crosses a module boundary. Every one of those is a property of a *repository*, and
|
||||
none of them is a property of a function.
|
||||
|
||||
Three of the twelve are worse than invisible — they are **quiet failures**, where the tool produced a clean
|
||||
report and every honesty counter agreed with it. The rung ladder labels a *verdict*; when no verdict is
|
||||
produced there is nothing to label. That is the failure mode a benchmark score cannot express at all, because
|
||||
the score is computed from the verdicts that exist.
|
||||
|
||||
So the corpus is necessary and not sufficient: it is the **holdout** that stops per-repository tuning, and it
|
||||
is the wrong instrument for finding out whether the tool works. Both instruments, or neither number means
|
||||
anything.
|
||||
|
||||
## The lesson that shaped the current specs
|
||||
|
||||
Nine engine defects were found in one session by pointing the tool at two real repositories. **Three were the
|
||||
|
||||
@@ -88,6 +88,24 @@ Everything here is in `contributor-scan`, group 2, and all of it is measurable o
|
||||
10. **Group 3–4 — ship it.** Contributor output, the Docker image, the memory-family decision, retiring
|
||||
`evidence_level` now that the rung carries the meaning.
|
||||
|
||||
## Alongside — keep the codebase from growing into the problem
|
||||
|
||||
> "we should make sure our code base here doesn't explode. for example we have a custom IR."
|
||||
|
||||
`.kiro/specs/ir-consolidation/` (brief, unapproved) separates two questions with opposite answers:
|
||||
|
||||
* **The source IR is already carried, not about to be added.** `semantic/` is 3,218 lines — 16% of the
|
||||
codebase — holding a hand-written IR and flat taint engine measured at **2.2% entailment against the CPG's
|
||||
41.3%**, still running as a proposer. Vine and Ghidra P-Code are *binary* IRs and do not help here; the
|
||||
work is subtraction. A candidate ~1,000-line deletion with a number attached.
|
||||
* **The missing abstraction is C arithmetic**, and there an existing IR is exactly right. GhidraPAL's
|
||||
three-valued-logic abstract interpreter over P-Code decides "can this index exceed this allocation", which
|
||||
is the class `c/memory` cannot see and every libpng overflow is. Vine is dormant since 2009 and is not the
|
||||
candidate.
|
||||
|
||||
The ordering constraint is the point: **question 1 lands before question 2 starts**, or adopting an IR makes
|
||||
the growth problem worse rather than better.
|
||||
|
||||
## After — the feedback loop
|
||||
|
||||
11. **`finding-feedback-loop`** (design generated, awaiting approval). Its ledger and dismissals are useful
|
||||
|
||||
Reference in New Issue
Block a user