mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
feat(model-grounded-detection): 4.2 constant abstraction, the third arbiter form
A configuration bug has no flow to follow and no guard to dominate.
CORS(app, origins="*") is dangerous because of the value it is SET TO, so the
arbiter evaluates the setting's arguments against the closed permissive set in
the obligation facts -- the third form beside taint reachability and guard
dominance, and the one Req 6.3 names.
ENTAILED a security setting is passed a literal in the permissive set
CORROBORATED the argument is computed, so constant abstraction cannot decide
it -- that residual is the judge's, never silently "safe"
(none) every literal is outside the set, or the call is not a setting
Two Joern node-shape bugs, both found by running it and both of the same class
as group 2's receiver bug -- the graph's indexing is not what the source text
suggests:
* a keyword argument (`origins="*"`) is an assignment-shaped node, so
isLiteral is false on the argument itself and the literal sits in its
subtree; literals are collected from the argument's AST now.
* Joern indexes the receiver at 0, positional arguments from 1, and NAMED
arguments at -1. Settings are configured overwhelmingly by keyword, so
argumentIndexGt(0) -- correct when counting arity for the taint shape test
-- dropped exactly the arguments that matter and every keyword-configured
setting read as "computed".
Live, deterministic, zero model calls:
create_app -> model_entailed CORS(app, origins = "*"): permissive literal "*"
safe_app -> no finding (origins = "https://app.example")
All three arbiter forms now work against a real CPG: taint reachability for the
flow families, guard dominance for absence, constant abstraction for config.
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
fec67253f3
commit
d9ceeb6a09
@@ -0,0 +1,78 @@
|
||||
"""model-grounded-detection task 4.2 / Req 6.3: the configuration arm is constant abstraction, not taint.
|
||||
|
||||
A config_secrets bug has no flow and no guard. `CORS(app, origins="*")` is not dangerous because untrusted
|
||||
input reaches it — nothing reaches it — but because the value it is *set to* is permissive. So the arbiter is
|
||||
abstract-value evaluation of the argument against the closed permissive set, which is the third form the
|
||||
design names alongside taint reachability and guard dominance.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _spec(): # type: ignore[no-untyped-def]
|
||||
from openultrasast.model.specs import ConfigSpec
|
||||
|
||||
return ConfigSpec(family="config_secrets", language="python",
|
||||
settings=("CORS", "set_cookie", "app.run"),
|
||||
permissive=("'*'", '"*"', "True", "0.0.0.0"))
|
||||
|
||||
|
||||
def _cpg(rows): # type: ignore[no-untyped-def]
|
||||
from openultrasast.cpg.backend import CpgResult
|
||||
|
||||
return CpgResult(cpg_path=Path("cpg.bin"), run=lambda q, p: rows)
|
||||
|
||||
|
||||
def test_a_permissive_literal_is_entailed() -> None:
|
||||
from openultrasast.model.config_value import verdict
|
||||
from openultrasast.model.ladder import Rung
|
||||
|
||||
rows = [{"setting": 'CORS(app, origins="*")', "line": "3", "method": "create_app",
|
||||
"literalArgs": ['"*"'], "args": ["app", '"*"']}]
|
||||
answer = verdict(_cpg(rows), _spec(), function="create_app")
|
||||
assert answer is not None and answer.rung is Rung.ENTAILED
|
||||
assert "*" in answer.witness and "CORS" in answer.witness
|
||||
|
||||
|
||||
def test_a_restrictive_literal_yields_no_finding() -> None:
|
||||
from openultrasast.model.config_value import verdict
|
||||
|
||||
rows = [{"setting": 'CORS(app, origins="https://app.example")', "line": "3", "method": "create_app",
|
||||
"literalArgs": ['"https://app.example"'], "args": ["app", '"https://app.example"']}]
|
||||
assert verdict(_cpg(rows), _spec(), function="create_app") is None
|
||||
|
||||
|
||||
def test_a_non_literal_argument_is_corroborated_not_entailed() -> None:
|
||||
"""The value is computed, so constant abstraction cannot decide it — that residual is the LLM's."""
|
||||
from openultrasast.model.config_value import verdict
|
||||
from openultrasast.model.ladder import Rung
|
||||
|
||||
rows = [{"setting": "CORS(app, origins=configured_origins)", "line": "3", "method": "create_app",
|
||||
"literalArgs": [], "args": ["app", "configured_origins"]}]
|
||||
answer = verdict(_cpg(rows), _spec(), function="create_app")
|
||||
assert answer is not None and answer.rung is Rung.CORROBORATED
|
||||
|
||||
|
||||
def test_a_setting_that_is_not_in_the_spec_is_ignored() -> None:
|
||||
from openultrasast.model.config_value import verdict
|
||||
|
||||
rows = [{"setting": 'print("*")', "line": "1", "method": "create_app", "literalArgs": ['"*"'], "args": ['"*"']}]
|
||||
assert verdict(_cpg(rows), _spec(), function="create_app") is None
|
||||
|
||||
|
||||
def test_a_failed_query_is_not_read_as_a_safe_configuration() -> None:
|
||||
from openultrasast.cpg.backend import CpgResult
|
||||
from openultrasast.model.config_value import verdict
|
||||
|
||||
assert verdict(CpgResult(cpg_path=Path("c.bin"), run=lambda q, p: None), _spec(), function="f") is None
|
||||
|
||||
|
||||
def test_the_verdict_is_deterministic() -> None:
|
||||
from openultrasast.model.config_value import verdict
|
||||
|
||||
rows = [{"setting": 'set_cookie("s", secure=False)', "line": "9", "method": "login",
|
||||
"literalArgs": ["True", "0.0.0.0"], "args": ["x"]}]
|
||||
cpg = _cpg(rows)
|
||||
assert verdict(cpg, _spec(), function="login") == verdict(cpg, _spec(), function="login")
|
||||
Reference in New Issue
Block a user