mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
docs(contributor-scan): 5.11 -- a detection strategy, not a verdict of impossible
"Structurally impossible" is a verdict, and a verdict is not a plan. Replacing
both structural-miss tasks with the one mechanism that covers them, because
they are the same shape: two halves of a path joined by a key that is a
literal in the source text.
hook: $_REQUEST -> ... -> return of set_current_page
key: 'wp_statistics_current_page' literal at both ends
return of apply_filters(key) -> ... -> $wpdb->get_row
field: $_POST -> ... -> assignment to $this->attachments
key: attachments a field name at both ends
read of $this->attachments -> ... -> unlink
Neither half is missing from the graph. Only the join is. So this is not a
request for a frontend to draw an edge it cannot draw -- it is a second
question asked with the query that already exists:
stage 1 the existing taint question against a synthetic endpoint: does
untrusted data reach a callback's return, or an assignment to
$this->F?
table built by reading literals, never inferring: add_filter('H', c)
against apply_filters('H', ...); $this->F = against $this->F
stage 2 does the apply_filters return, or the field read, reach a sink?
join on the key, with the RUNG carrying the join's uncertainty -- one
registered callback and a literal key entails; several callbacks or
a computed hook name corroborates, and the witness says which
"Any hook may reach any handler" is refused absolutely: a complete graph over
the plugin would entail everything.
No new dependency, no CPG mutation, no IR -- both stages ride the batch that
already runs, which is the point of expressing it as a query-level join.
It also recovers the precision fix 5.8 had to refuse. With the field half
working, _delete_files() is reached through $this->attachments rather than
through $this being tainted wholesale, so the receiver can then leave
parameter sources and take PMPro's 11 receiver-sourced findings with it.
5.8's numbers are the before-side of that measurement, and both observables
are pairs already pinned.
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
2ba1aaf649
commit
e41d6dd7ea
@@ -113,6 +113,17 @@ cross it, and the honest description is not "we missed it" but "the graph does n
|
||||
plugin data travels this way. It is the single largest structural gap for PHP, and it is not a fact-table
|
||||
problem.
|
||||
|
||||
It is also not a permanent one, and "structurally impossible" would be the wrong thing to leave here. Note
|
||||
what is and is not missing: `$_REQUEST` reaching `set_current_page`'s return is a path the graph *has*, and
|
||||
`apply_filters`' return reaching `$wpdb->get_row` is a path the graph *has*. Only the join between them is
|
||||
absent — and the key it joins on, `'wp_statistics_current_page'`, is a string literal written at both ends.
|
||||
The same is true of `$this->attachments` in MW WP Form, where the key is a field name.
|
||||
|
||||
So the strategy is two-stage taint with a link table: ask the existing query for each half against a
|
||||
synthetic endpoint, build the table by reading literals rather than inferring anything, and join. The rung
|
||||
carries the join's uncertainty — one registered callback and a literal key entails, several callbacks or a
|
||||
computed hook name corroborates. Task 5.11 states it, with both pinned pairs as its observable.
|
||||
|
||||
What the engine reports on that plugin instead is two other sites — `getTop:406` and `TotalCount:443` — the
|
||||
same weakness class at the wrong lines, identical on both sides, so the pair does not separate. They are not
|
||||
noise: upstream now annotates both with `// phpcs:ignore WordPress.DB.PreparedSQL...`, and later rewrote
|
||||
|
||||
Reference in New Issue
Block a user