Repository navigation
feat: let advisory entry points name the arguments the attacker must control - #147
Merged
Merged
Conversation
…control An advisory entry point was an ADVISORY sink on every argument, so attacker data in any argument made the call exploitable. An entry point may now name its attacker_arguments, by keyword and position, a variadic one taking every later position; attacker input elsewhere leaves the call reachable. Each taint flow records how its value is passed to the sink, and flows differing only in that are merged, so detectors see the same flows as before.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #145.
An advisory entry point was an
ADVISORYsink on every argument, so attacker data in any argument made the callexploitable-vulnerability(CRITICAL). An entry point may now name the arguments the attacker must control.argumentis the keyword name;positioncounts as for argument conditions (from 0, a method's receiver excluded)."variadic": trueextends a position to every later one, as forsafe_join(directory, *pathnames):{"position": 1, "variadic": true}.affecteddo not change.*argsand**kwargsAn argument unpacked with
*or**has no position and no keyword, so the engine cannot tell which argument it fills. It counts, for two reasons:def fetch(*args, **kwargs): return requests.get(*args, **kwargs)would no longer reach the URL.The cost:
fetch(URL, **{'data': attacker})stays exploitable. Detector sinks make the opposite choice (Sink.kinds_atgives an unpacked argument no restricted kind), because a sink model states what it accepts; here the question is whether the attacker controls the argument at all. Tests pin both the rule and the wrapper case, and a mutation to "does not count" makes 4 of them fail.Design
report()already knew the position or keyword of the tainted argument, for direct calls and through function summaries.TaintFlownow keeps it inpassed_as.passed_asare merged. Without this, a value passed twice (f(x, key=x)) would become two flows, and detectors would report it twice. They see exactly the flows they saw before.correlate()checks each flow against the entry point of each advisory, so two advisories on the same symbol can name different arguments.repr(advisories).Measured
The curated CVE-2024-49766 data was taken from the plugins repository, and
attacker_argumentswas added in a scratch copy, not in this PR:send_from_directory:path, position 1;safe_join: position 1, variadic.send_from_directory("uploads", name), route<path:name>send_from_directory("reports", "report.pdf", download_name=request.args["name"])send_from_directory(request.args["dir"], "report.pdf")Out of scope
Keys versus values of a
**mapping. Django's_connector(CVE-2025-64459) needs the keys, and taint does not tell them apart.Tests
tests/test_attacker_arguments.py, 21 tests: