mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
feat: the first real CVE, found in production plugin code
CVE-2023-23488 is detected at
classes/class.memberorder.php:936:getMemberOrderByCode -- the exact line
verified in the source, in unmodified Paid Memberships Pro 2.9.7.
A two-file slice carrying both ends of the CVE, 2885 lines, loads and
queries in 122 seconds and reports 16 entailed injection findings.
**The other fifteen are not noise.** The file holds 26 `$wpdb` query calls
and **zero** of them use `->prepare`; all 26 interpolate or concatenate a
variable. The engine reports 16 of 26, so it under-reports rather than
over-reports, and every sampled finding is a genuine unprepared query --
`get_row("... WHERE id = '$id'")`, `get_var("... WHERE ID = '" .
$this->user_id . "'")`. CVE-2023-23488 is simply the instance that got an
identifier, because it is reachable unauthenticated; the rest are the same
defect with different reachability.
That answers the question that prompted this: whether the system can find
one real CVE. It can, in production code, at the exact line, in two
minutes, for a cent. What it could not do was survive its own plumbing at
637 files -- four separate quiet failures on this one checkout, all between
the scan and the arbiter, none of them in the analysis.
What this does NOT settle is recorded with it: the full checkout still does
not load and that boundary is unmeasured; whether php2cpg resolves
`new X()` and `$this->method()` is still unknown, since this slice reached
the sink through a same-function flow rather than across the object; and
one CVE on one plugin is not the class-by-class table over several plugins
that 5.8 asks for.
On cutting the input with a model, proposed when size looked like the
blocker: the evidence argues for scoping rather than triage. Two of 637
files found the CVE, task 2.10 already scopes by what a project declares it
ships, and diff-scoping is this spec's thesis. A model choosing what to cut
adds a fifth quiet-failure surface -- drop the file holding the bug and the
scan reports clean with nothing recording why, which is the shape of all
four failures found today. The reverse direction is where it fits: ranking
which regions get the budget, not choosing what to remove.
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
21fdb554aa
commit
96e7476c6d
@@ -541,6 +541,14 @@
|
|||||||
- Until this is answered, PHP detection is demonstrated only on files small enough to build cleanly, and
|
- Until this is answered, PHP detection is demonstrated only on files small enough to build cleanly, and
|
||||||
no claim about WordPress can be made either way.
|
no claim about WordPress can be made either way.
|
||||||
- Observable: the largest PHP tree that loads and queries, measured, with the failure boundary recorded.
|
- Observable: the largest PHP tree that loads and queries, measured, with the failure boundary recorded.
|
||||||
|
- **Partly answered 2026-09-09, and it produced the first real CVE.** A two-file slice carrying both ends
|
||||||
|
of the CVE -- `classes/class.memberorder.php` and `includes/rest-api.php`, 2885 lines -- loads, queries
|
||||||
|
in 122 seconds, and reports **CVE-2023-23488 at class.memberorder.php:936:getMemberOrderByCode**, the
|
||||||
|
exact verified line. 16 entailed injection findings, and the file holds 26 `$wpdb` query calls of which
|
||||||
|
**zero** use `->prepare`, so the engine under-reports rather than over-reports. See
|
||||||
|
`benchmarks/measurements/2026-09-09-pmpro-cve-found.json`.
|
||||||
|
- Still open: the 637-file boundary itself, and whether the REST handler two calls away can reach it --
|
||||||
|
this slice found the sink through a same-function flow, not across the object.
|
||||||
- _Requirements: 4.2, 4.3, 9.1_
|
- _Requirements: 4.2, 4.3, 9.1_
|
||||||
- _Depends: 5.7_
|
- _Depends: 5.7_
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"are_the_other_fifteen_noise": {
|
||||||
|
"answer": "No. The file is systemically unprepared.",
|
||||||
|
"counted": {
|
||||||
|
"engine_entailed": 16,
|
||||||
|
"unprepared_with_a_variable": 26,
|
||||||
|
"using_prepare": 0,
|
||||||
|
"wpdb_query_calls": 26
|
||||||
|
},
|
||||||
|
"reading": "Every sampled finding is a genuine unprepared query. The engine reports 16 of 26 such sites, so it UNDER-reports rather than over-reports here. CVE-2023-23488 is simply the instance that got an identifier, because it is reachable unauthenticated; the rest are the same defect with different reachability.",
|
||||||
|
"sampled": {
|
||||||
|
"1073": "get_row(\"... WHERE ID = '\" . $this->user_id . \"'\")",
|
||||||
|
"1512": "get_var(\"... WHERE code = '$code' LIMIT 1\")",
|
||||||
|
"671": "get_row(\"... WHERE id = '$id' LIMIT 1\")",
|
||||||
|
"705": "get_var(\"... WHERE ID = '\" . $this->user_id . \"'\")"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generated": "2026-09-09",
|
||||||
|
"on_cutting_the_input_with_a_model": "Proposed by the maintainer when size looked like the blocker. The evidence argues for scoping rather than triage: two of 637 files found the CVE in 122 seconds, and task 2.10 already scopes by what a project declares it ships while diff-scoping is this spec's actual thesis. A model deciding what to cut adds a FIFTH quiet-failure surface -- if it drops the file holding the bug, the scan reports clean and nothing records why, which is the exact shape of all four failures found today. The reverse direction is where a model fits: not choosing what to remove, but ranking which regions get the budget first.",
|
||||||
|
"reading": "CVE-2023-23488 is detected at classes/class.memberorder.php:936:getMemberOrderByCode -- the exact line verified in the source, in unmodified plugin code. The engine works; what has been unfit is the plumbing around it, which produced four separate quiet failures on this one checkout before a CPG it could load reached the arbiter.",
|
||||||
|
"scan": {
|
||||||
|
"build_seconds": 9.0,
|
||||||
|
"cve_found": "model_entailed injection class.memberorder.php:936:getMemberOrderByCode",
|
||||||
|
"entailed": 16,
|
||||||
|
"input": "two files carrying both ends of the CVE: classes/class.memberorder.php and includes/rest-api.php, 2885 lines",
|
||||||
|
"query_seconds": 110.9,
|
||||||
|
"regions": 57,
|
||||||
|
"total_seconds": 122.0
|
||||||
|
},
|
||||||
|
"spec": "contributor-scan 5.10 -- the first real CVE found in production code",
|
||||||
|
"what_it_does_not_settle": [
|
||||||
|
"The full 637-file checkout still does not load, and that boundary is unmeasured.",
|
||||||
|
"Whether php2cpg resolves `new X()` and `$this->method()` is still unknown -- this slice found the sink through a same-function flow, not through the REST handler two calls away.",
|
||||||
|
"One CVE on one plugin. The class-by-class table over several plugins (5.8) is still the artifact worth teaching from."
|
||||||
|
],
|
||||||
|
"what_this_settles": "The question was whether the system can find one real CVE. It can, in production code, at the exact line, in two minutes, for a cent. What it could not do was survive its own plumbing at 637 files."
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user