mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
fix(mapping): an array callable registers a handler too
`array( $this, 'method' )` is the normal way a class-based WordPress plugin registers a callback, and the recogniser only matched the bare string form. The cost was precise. Paid Memberships Pro registers every REST route that way, so `pmpro_rest_api_get_order` -- the entry point that receives CVE-2023-23488's tainted `code` parameter -- was classified as a plain function at rank 0.30, position 1036 of 1577, below the 500-region budget. It was never asked about. Meanwhile `getMemberOrderByCode`, the sink two calls away, WAS scanned at position 450 and found nothing, because its `$code` is an ordinary parameter and only an entry point's parameters are treated as untrusted. So the scan examined the sink, missed the source, and reported the plugin clean. Recognising the array callable puts the handler at position 290 with rank 0.80 and `source=entry_point`, which is what gives it the interprocedural question that task 2.4 built for exactly this shape. Gates byte-identical. 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
92677136d7
commit
9020318a83
@@ -302,3 +302,33 @@ def test_every_php_function_becomes_a_region(tmp_path: Path) -> None:
|
||||
regions = regions_for(analyze_entry_points(tmp_path, targets), targets)
|
||||
|
||||
assert {region.function for region in regions} >= {"a", "b"}
|
||||
|
||||
|
||||
def test_an_array_callable_is_a_handler_too(tmp_path: Path) -> None:
|
||||
"""`array( $this, 'method' )` is the normal form in a class-based plugin.
|
||||
|
||||
Paid Memberships Pro registers every REST route that way, and matching only the string form left its
|
||||
handlers ranked as plain functions below the scan budget -- so the entry point carrying CVE-2023-23488's
|
||||
source was never asked about, while the sink two calls away was.
|
||||
"""
|
||||
from openultrasast.mapping import analyze_entry_points
|
||||
from openultrasast.preprocess import preprocess_repository
|
||||
|
||||
(tmp_path / "api.php").write_text(
|
||||
"<?php\n"
|
||||
"register_rest_route( $ns, '/order', array( array(\n"
|
||||
" 'methods' => 'GET',\n"
|
||||
" 'callback' => array( $this, 'get_order' ),\n"
|
||||
" 'permission_callback' => array( $this, 'permissions_check' )\n"
|
||||
") ) );\n"
|
||||
"add_action('wp_ajax_nopriv_fetch', array( $this, 'fetch' ));\n"
|
||||
"function get_order($request) { echo 1; }\n"
|
||||
"function fetch() { echo 2; }\n"
|
||||
)
|
||||
_, targets = preprocess_repository(tmp_path)
|
||||
|
||||
by_name = {entry.function_name: entry for entry in analyze_entry_points(tmp_path, targets)}
|
||||
|
||||
assert by_name["get_order"].kind == "route", "an array callable registers a route"
|
||||
assert by_name["get_order"].access_level == "authenticated", "its permission_callback is not __return_true"
|
||||
assert by_name["fetch"].access_level == "public", "nopriv, through an array callable"
|
||||
|
||||
Reference in New Issue
Block a user