mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-17 20:19:29 +00:00
Externalize detection rules to versioned TOML and remove rule-local severity, so rules detect and the central CWE policy decides severity — fixing "rules too influential / not centrally managed". Zero-dependency; detection is byte-identical (benchmark recall 44/47 = 93.6%, FP 0% unchanged) and the 90/10 gate holds. - RulesetStore (ruleset/store.py + ruleset/<lang>/rules.toml): PatternRule as data (rule_id, title, languages, cwe, tags, pattern, status, min_evidence_level, precision_estimate, version) with NO severity; load_ruleset (sorted, with optional rule_policy.json ledger overlay) and a stdlib TOML write_ruleset. The 32 rules were generated from the prior PATTERN_RULES with a verified exact round-trip (pattern/cwe/languages/tags/title). - findings.py: drop the hardcoded PatternRule class + PATTERN_RULES tuple; load the default ruleset from TOML; quick_scan_findings(root, targets, rankings, ruleset, policy) resolves each finding's severity from policy via resolve_severity (SEVERITY_LABEL maps 0-5 -> string) and tags findings with their rule status. - Three-status volume control: StaticFinding gains status (default "enabled"); disabled rules never fire; shadow findings are partitioned out of the report and score in the CLI (written to shadow_findings.json) — no shadow rules by default. - Emission floors (RulesetConfig.min_emit_priority / min_emit_precision, default 0.0 = emit all) replace "every match is a finding". - CLI loads the ruleset as a stage and uses it for the fail-loud policy check, detection, hunter pool, and the score CWE map. Wheel ships the ruleset TOML. 85 tests pass; ruff + mypy clean. Spec tasks 3.1-3.4 checked off. Co-Authored-By: Claude Opus 4.8 <[email protected]>
132 lines
3.7 KiB
TOML
132 lines
3.7 KiB
TOML
[[rule]]
|
|
rule_id = "js-command-exec"
|
|
title = "Node child_process command execution needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-78"
|
|
tags = ["syscall_entry"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\b(exec|execSync)\s*\('''
|
|
|
|
[[rule]]
|
|
rule_id = "js-deserialize"
|
|
title = "JavaScript unsafe deserialization needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-502"
|
|
tags = ["deserialization"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\b(unserialize)\s*\('''
|
|
|
|
[[rule]]
|
|
rule_id = "js-dom-xss"
|
|
title = "DOM sink with untrusted input needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-79"
|
|
tags = ["injection"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\.(innerHTML|outerHTML)\s*=\s*[^\n]*\b(?:req|request|location|document\.location)'''
|
|
|
|
[[rule]]
|
|
rule_id = "js-eval"
|
|
title = "Dynamic JavaScript evaluation needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-95"
|
|
tags = ["syscall_entry"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\b(eval)\s*\('''
|
|
|
|
[[rule]]
|
|
rule_id = "js-function-constructor"
|
|
title = "JavaScript Function constructor needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-95"
|
|
tags = ["syscall_entry"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''new\s+(Function)\s*\('''
|
|
|
|
[[rule]]
|
|
rule_id = "js-path-traversal"
|
|
title = "Node filesystem access with external input needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-22"
|
|
tags = ["filesystem_entry"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\bfs\.(readFile|readFileSync|writeFile|writeFileSync|createReadStream|unlink|unlinkSync)\s*\(\s*[^\n]*\b(?:req|request)\.'''
|
|
|
|
[[rule]]
|
|
rule_id = "js-spawn-shell"
|
|
title = "Node spawn with shell needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-78"
|
|
tags = ["syscall_entry"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\b(spawn|spawnSync)\s*\([^\n]*shell\s*:\s*true'''
|
|
|
|
[[rule]]
|
|
rule_id = "js-sql-injection"
|
|
title = "JavaScript SQL string composition needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-89"
|
|
tags = ["injection"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\.(query|execute)\s*\(\s*[^\n]*(?:\$\{|\+\s*[A-Za-z_$])'''
|
|
|
|
[[rule]]
|
|
rule_id = "js-ssrf"
|
|
title = "JavaScript outbound request with external input needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-918"
|
|
tags = ["network_entry"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\b(axios|fetch|got)\s*[.(][^\n]*\b(?:req|request)\.'''
|
|
|
|
[[rule]]
|
|
rule_id = "js-weak-hash"
|
|
title = "JavaScript weak hash needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-327"
|
|
tags = ["crypto"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''createHash\s*\(\s*[\"'](md5|sha1)[\"']'''
|
|
|
|
[[rule]]
|
|
rule_id = "js-xss-response"
|
|
title = "Unsanitized HTTP response reflection needs review"
|
|
languages = ["javascript", "typescript"]
|
|
cwe = "CWE-79"
|
|
tags = ["injection"]
|
|
status = "enabled"
|
|
min_evidence_level = "static_corroboration"
|
|
precision_estimate = 0.0
|
|
version = "1"
|
|
pattern = '''\.(send|write|end)\s*\(\s*[^\n]*\b(?:req|request)\.(?:query|params|body)'''
|