mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-19 04:59:28 +00:00
fix(taint): a filter returns its value argument; a source is the access, not a call around it
The apply_filters class from the second PMPro adjudication (2 of 3
remaining false positives): `apply_filters('pmpro_random_code', $code,
$this)` returned whatever $this carried, and a report's `$type` reached SQL
only as an extra filter argument. Two causes, both fixed generally:
- The dispatch fact now says what an apply call RETURNS: `returns` names
the calls whose result is the dispatched value and `value_arg` its
position (WordPress: apply_filters/apply_filters_ref_array return
argument 2; do_action returns nothing). A path through such a call must
ENTER by that argument -- the first of the run of the call's arguments
before it, because the engine hops between sibling arguments
($_GET["c"] -> md5("x") -> apply_filters). Loaded and validated as data;
the query knows no framework.
- A call was a source when the pattern appeared anywhere in its text, so
`apply_filters(..., $_GET["c"])` and `sanitize_text_field($_POST[..])`
were sources themselves -- the "a token matches the thing it names"
invariant. A call is now a source when the pattern names its callee,
receiver or the access it is; the inner access stays a source.
Controls: dispatch facts load/validate; a real-Joern case with request
data as filter context (quiet) and as the filtered value (found). 1,453
host and 18 query tests pass.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f1e43d3646
commit
7b8ff3cf44
@@ -72,6 +72,14 @@ class DispatchFact:
|
||||
register: tuple[str, ...]
|
||||
apply: tuple[str, ...]
|
||||
language: str
|
||||
# What an apply call RETURNS. `returns` names the apply calls whose result is the dispatched value, and
|
||||
# `value_arg` is that value's argument position (1-based, receiver excluded): WordPress's
|
||||
# `apply_filters('hook', $value, ...$context)` returns the filtered `$value`, and its context arguments
|
||||
# never become the result. An apply call not named in `returns` returns nothing a flow can carry
|
||||
# (`do_action`). Without this the engine let EVERY argument reach the return: PMPro's random order code
|
||||
# came out "tainted" because `$this` was passed as filter context. Empty keeps the engine's default.
|
||||
returns: tuple[str, ...] = ()
|
||||
value_arg: int = 0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -164,11 +172,30 @@ def _dispatches(value: object, language: str, path: Path) -> list[DispatchFact]:
|
||||
register=_strings(item.get("register"), "register", path),
|
||||
apply=_strings(item.get("apply"), "apply", path),
|
||||
language=language,
|
||||
returns=_returning(item, path),
|
||||
value_arg=_value_arg(item, path),
|
||||
)
|
||||
)
|
||||
return facts
|
||||
|
||||
|
||||
def _returning(item: dict[str, object], path: Path) -> tuple[str, ...]:
|
||||
returns = _strings(item.get("returns", []), "returns", path)
|
||||
unknown = set(returns) - set(_strings(item.get("apply"), "apply", path))
|
||||
if unknown:
|
||||
raise FactLoadError(f"dispatch {item.get('id')!r} in {path}: returns names calls that are not apply calls: {sorted(unknown)}")
|
||||
return returns
|
||||
|
||||
|
||||
def _value_arg(item: dict[str, object], path: Path) -> int:
|
||||
value = item.get("value_arg", 0)
|
||||
if not isinstance(value, int) or isinstance(value, bool) or value < 0:
|
||||
raise FactLoadError(f"dispatch {item.get('id')!r} in {path}: value_arg must be a non-negative integer")
|
||||
if item.get("returns") and value < 1:
|
||||
raise FactLoadError(f"dispatch {item.get('id')!r} in {path}: returns needs the value's argument position")
|
||||
return value
|
||||
|
||||
|
||||
def _layouts(value: object, language: str, path: Path) -> list[LayoutFact]:
|
||||
facts: list[LayoutFact] = []
|
||||
for item in _items(value):
|
||||
|
||||
Reference in New Issue
Block a user