diff --git a/src/openultrasast/cpg/queries/taint.sc b/src/openultrasast/cpg/queries/taint.sc index 5524f84..5c13769 100644 --- a/src/openultrasast/cpg/queries/taint.sc +++ b/src/openultrasast/cpg/queries/taint.sc @@ -710,8 +710,11 @@ def guardsIn(root: io.shiftleft.codepropertygraph.generated.nodes.AstNode, names: Set[String]): List[io.shiftleft.codepropertygraph.generated.nodes.Call] = if (guardNames.isEmpty) Nil else + // Only the TESTED value is validated -- the first argument: `in_array`'s needle, the URL a redirect check is + // given. PMPro's `in_array( 'E', $levels )` asks whether a constant is in `$levels`; with any argument + // counted, it discharged a flow through `$levels` itself. root.ast.isCall.l.filter(g => guardNames.contains(g.name)).filter { g => - g.argument.l.exists(_.ast.exists { + g.argument.l.filter(_.argumentIndex == 1).exists(_.ast.exists { case i: io.shiftleft.codepropertygraph.generated.nodes.Identifier => names(i.name) || names(i.code.trim) case c: io.shiftleft.codepropertygraph.generated.nodes.Call if c.name == FIELD_ACCESS => names(c.code.trim) case _ => false diff --git a/tests/test_cpg_queries_compile.py b/tests/test_cpg_queries_compile.py index a3142ea..7aa9120 100644 --- a/tests/test_cpg_queries_compile.py +++ b/tests/test_cpg_queries_compile.py @@ -1400,8 +1400,11 @@ def test_an_allowlist_check_guards_its_branch_and_its_ternary_arm(tmp_path: Path ' else { $o = " ORDER BY u.{$s} "; }\n' " $o = apply_filters( 'sort', $o, $s );\n" ' return $wpdb->query( "SELECT 1 FROM t {$o}" ); }\n' + "function haystack() { global $wpdb; $l = $_POST['l'];\n" + " if ( in_array( 'E', $l, true ) ) { return $wpdb->query( \"SELECT 1 FROM t WHERE u = {$l[0]}\" ); }\n" + " return null; }\n" ) - names = ("ternary", "wrong_arm", "branch", "else_branch", "stored_in_branch", "stored_in_else") + names = ("ternary", "wrong_arm", "branch", "else_branch", "stored_in_branch", "stored_in_else", "haystack") common = { "sources": ",".join(spec.sources), "sinks": ",".join(spec.sinks), @@ -1413,4 +1416,4 @@ def test_an_allowlist_check_guards_its_branch_and_its_ternary_arm(tmp_path: Path } payload = _taint_rows(tmp_path, "php2cpg", {"app.php": app}, {n: {**common, "function": n} for n in names}) reported = {n for n in names if _unsanitized(payload, n)} - assert reported == {"wrong_arm", "else_branch", "stored_in_else"}, {n: payload[n] for n in names} + assert reported == {"wrong_arm", "else_branch", "stored_in_else", "haystack"}, {n: payload[n] for n in names}