mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
fix(specs): the php2cpg "blocker" was the shim, not the frontend
Task 5.5 recorded that php2cpg emits a CPG containing only one PHP file --
the last alphabetically -- and called it a blocker for the WordPress
target. Rerun with a native php-cli, as asked, and it is not true.
php 8.3.6, no shim, same joern 4.0.623, same two files:
files: plugin.php, vuln.php
methods: mp_fetch_report, mp_save_report, mp_render_box, mp_helper,
get_user, safe_user, show, run
Both files, all eight methods, and no PHP-Parser banner warning at all --
the banner that looked like the thread to pull was a symptom of the same
thing and does not occur natively.
The cause was the workaround. This machine has no PHP interpreter, so the
shim ran each `php` invocation in its own container; php2cpg drives
PHP-Parser once per file, and that per-invocation isolation kept only one
file's JSON.
**The lesson is worth more than the fix.** Two independent reproductions
agreed, and both were measured through the same broken instrument. A
consistent result is not a correct one when every measurement shares an
apparatus -- the same trap as a corpus that cannot see the defect it is
scoring, which is this session's other recurring finding.
And with the instrument fixed, 5.4 is demonstrably done. A two-file PHP
tree yields 10 function-scoped regions and 7 entailed findings in 15
seconds: SQL injection in both WordPress handlers, XSS in the shortcode
renderer, and all three of the original probe's. safe_user is correctly
absent, its mysqli_real_escape_string dropping it to corroborated. The
wp_ajax_nopriv_ handler ranks 1.0 and the plain helper 0.3.
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
0ffa99b5e6
commit
f488e625c2
@@ -425,7 +425,7 @@
|
||||
- _Requirements: 2.1, 8.1, 9.1_
|
||||
- _Depends: 5.1_
|
||||
|
||||
- [ ] 5.5 php2cpg emits a CPG containing one file
|
||||
- [x] 5.5 php2cpg emits a CPG containing one file — NOT A DEFECT, it was the shim
|
||||
- **Found by 5.4 and it blocks the WordPress target.** A CPG built over two PHP files contains only one,
|
||||
and the survivor is the last alphabetically. Reproduced twice on independent samples; both files parse
|
||||
cleanly under `php -l` and under PHP-Parser directly, and `joern-parse` reports success either way.
|
||||
@@ -439,6 +439,13 @@
|
||||
failure Req 5.6 was approved for.
|
||||
- Observable: a CPG over N PHP files contains N files, or a recorded reason it cannot with the version and
|
||||
the reproduction.
|
||||
- **Resolved 2026-09-09: there was no defect.** Rerun with a native php-cli (8.3.6, no shim) over the same
|
||||
two files and the CPG contains both, all eight methods, and no PHP-Parser banner warning at all. The
|
||||
shim ran each `php` invocation in its own container -- needed because this machine has no interpreter --
|
||||
and php2cpg drives PHP-Parser per file, so that isolation kept only one file's JSON.
|
||||
- **The lesson is worth more than the fix.** Two independent reproductions agreed, and both were measured
|
||||
through the same broken instrument. A consistent result is not a correct one when every measurement
|
||||
shares an apparatus, which is the same trap as a corpus that cannot see the defect it is scoring.
|
||||
- _Requirements: 4.3, 5.6, 9.1_
|
||||
- _Depends: 5.4_
|
||||
|
||||
|
||||
@@ -1,19 +1,37 @@
|
||||
{
|
||||
"caveat": "Every PHP number here comes from probe files of a dozen lines. The recogniser is validated on a WordPress-shaped sample, not on WordPress.",
|
||||
"generated": "2026-09-09",
|
||||
"native_run": {
|
||||
"build_seconds": 4.06,
|
||||
"entailed": 7,
|
||||
"environment": "eclipse-temurin:21-jre-noble + php-cli 8.3.6 + the same joern 4.0.623, no shim",
|
||||
"findings": [
|
||||
"plugin.php:8:mp_fetch_report injection $_GET['id'] -> concat -> mysqli_query",
|
||||
"plugin.php:9:mp_fetch_report output_encoding echo of the query result",
|
||||
"plugin.php:14:mp_save_report injection $_POST['title'] -> concat -> mysqli_query",
|
||||
"plugin.php:18:mp_render_box output_encoding echo $_GET['banner']",
|
||||
"vuln.php:5:get_user injection $_GET['name'] -> concat -> mysqli_query",
|
||||
"vuln.php:12:show output_encoding echo $_GET['msg']",
|
||||
"vuln.php:13:run injection system($_POST['cmd'])"
|
||||
],
|
||||
"query_seconds": 10.94,
|
||||
"reading": "Every intended vulnerability in both files is found, at the right function and line, with the WordPress-registered handlers ranked above the plain helper. safe_user is correctly absent -- its mysqli_real_escape_string drops it to corroborated, which the free pass does not report.",
|
||||
"regions": 10
|
||||
},
|
||||
"one_verdict_per_region_fixed": {
|
||||
"libpng": "1 -> 2 entailed; the second (contrib/libtests/makepng.c:1580:strstash) was hidden by the collapse. Neither is validated and both are in contrib/.",
|
||||
"php_probe": "2 of 3 -> 3 of 3; the SQL injection at vuln.php:5 had been losing to `system` on flow length",
|
||||
"vampi": "6 entailed, unchanged -- and now with line numbers on access-control findings from task 2.7",
|
||||
"what": "taint.verdicts() returns one verdict per distinct SINK SITE, strongest first, and its first element is exactly what verdict() returns -- so the pair path and every committed measurement resting on it are unchanged, and the gates are byte-identical."
|
||||
},
|
||||
"reading": "Both halves of 5.4 are implemented and one is blocked by the frontend. Per-site verdicts take the PHP probe from 2 of 3 to 3 of 3 and surface a second libpng finding that the collapse was hiding. The WordPress recogniser reads declared access correctly and turns one file-level region into ten function-scoped ones. But php2cpg emits a CPG containing only ONE PHP file in this configuration, which blocks the WordPress target until it is understood.",
|
||||
"reading": "Both halves of 5.4 work, and the frontend blocker recorded against them was the local shim rather than php2cpg. With a native php-cli a two-file PHP tree yields 10 function-scoped regions and 7 entailed findings at the right locations, in 15 seconds.",
|
||||
"spec": "contributor-scan 5.4 (Req 2.1, 8.1, 9.1)",
|
||||
"the_blocker": {
|
||||
"detail": "A CPG built over two PHP files contains only one of them, and the survivor is the last alphabetically. Reproduced twice: {plugin.php, vuln.php} kept vuln.php; {only_fn.php, stmt_then_fn.php} kept stmt_then_fn.php. Both files parse cleanly under `php -l` and under PHP-Parser directly, and joern-parse reports success. php2cpg logs 'Found warning in PHP-Parser JSON output' naming the surviving file, which is PHP-Parser's own `====> File X:` banner appearing in what php2cpg expects to be pure JSON.",
|
||||
"cause": "The shim ran each `php` invocation in its own container, which this machine needed because it has no PHP interpreter. php2cpg drives PHP-Parser per file and something in that per-invocation isolation kept only one file's JSON. The `====> File X:` banner that looked like the thread to pull was a symptom of the same thing, and it does not occur natively.",
|
||||
"detail": "A CPG over two PHP files contained only the last one alphabetically, reproduced twice. That was recorded as a php2cpg blocker for the WordPress target. It was wrong: rerun with a NATIVE php-cli (php 8.3.6, no shim) over the same two files, the CPG contains both, all eight methods, and no PHP-Parser banner warning appears at all.",
|
||||
"id": "php2cpg-emits-one-file",
|
||||
"not_yet_isolated": "This machine has no PHP interpreter, so php2cpg was driven through a container shim. The banner comes from PHP-Parser rather than from the shim, which makes a shim-only cause unlikely but not excluded. Rerunning with a native php-cli -- which the shipped image has -- is the first step.",
|
||||
"why_it_blocks_wordpress": "A plugin is many files. A scan that silently covers one of them and reports success is the quiet failure Req 5.6 was approved for, and it would read as a clean bill of health."
|
||||
"lesson": "The workaround was the defect. Two independent reproductions agreed and both were measured through the same broken instrument, which is exactly how a measurement lies: it was consistent and wrong.",
|
||||
"status": "NOT A DEFECT -- it was the container shim, resolved 2026-09-09"
|
||||
},
|
||||
"wordpress_recogniser": {
|
||||
"access_is_declared_not_guessed": "The hook name IS the declaration: wp_ajax_nopriv_* is WordPress saying logged-out callers reach this, so it is public; wp_ajax_* fires only for logged-in ones. permission_callback => __return_true declares a REST route open. That is the declared-provenance signal task 2.8 needs, arriving from a second framework.",
|
||||
|
||||
Reference in New Issue
Block a user