Prerelease cleanup (#46)

* feat: Add const_bound_vars tracking to prevent false positives in ownership checks

* feat: Introduce field interner and typed bounded vars for enhanced type tracking

* feat: Add typed_call_receivers and typed_bounded_dto_fields for enhanced type tracking

* feat: Centralize method name extraction with bare_method_name helper

* feat: Implement Phase-6 hierarchy fan-out for runtime virtual dispatch

* feat: Enhance C++ taint tracking with additional container operations and inline method resolution

* feat: Introduce field-sensitive points-to analysis for enhanced resource tracking

* feat: Implement Pointer-Phase 6 subscript handling for enhanced container analysis

* test: Add comprehensive tests for JavaScript control flow constructs and lattice operations

* docs: Update advanced analysis documentation with field-sensitive points-to and hierarchy fan-out details

* test: Add comprehensive tests for lattice algebra laws and SSA edge cases

* feat: Add destructured session user handling and safe user ID access patterns

* feat: Implement row-population reverse-walk for enhanced authorization checks

* feat: Enhance authorization checks with local alias chain for self-actor types

* feat: Introduce ActiveRecord query safety checks and enhance snippet extraction

* feat: Implement chained method call inner-gate rebinding for SSRF prevention

* feat: Add observability and error modules, enhance debug functionality, and implement theme context

* feat: Remove Auth Analysis page and update navigation to redirect to Explorer

* feat: Optimize SSA lowering by sharing results between taint engine and artifact extractor

* feat: Optimize SSA lowering by sharing results between taint engine and artifact extractor

* feat: Reset path-safe-suppressed spans before lowering to maintain analysis integrity

* fix(ssa): ungate debug_assert_bfs_ordering for release-tests build

The helper at src/ssa/lower.rs was gated `#[cfg(debug_assertions)]` while
the unit test at the bottom of the file was gated only `#[cfg(test)]`.
Since `cfg(test)` is set in release builds with `--tests` but
`cfg(debug_assertions)` is not, `cargo build --release --tests` failed
with E0425. Removing the gate fixes the build; the body is `debug_assert!`
only, so the helper is free in release. Also drop the gate at the call
site to avoid a `dead_code` warning when the lib is built without
`--tests`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(closure-capture): flip JS/TS fixtures to required-finding

The JS and TS closure-capture fixtures pinned the old broken behaviour
via `forbidden_findings: [{ "id_prefix": "taint-" }]`. The engine now
correctly traces taint through the closure boundary (env source captured
by an arrow function, sunk via `child_process.exec` inside the body), so
the formerly-forbidden finding is a true positive.

Match the Python sibling's shape — `required_findings` with
`id_prefix` + `min_count` plus a small `noise_budget` — and rewrite the
companion READMEs and the phase8_fragility_tests doc-comments from
"known gap" to "regression guard".

Verified:
- cargo test --release --test phase8_fragility_tests → 8/8 pass
- cargo test --release --lib bfs_assertion → pass
- corpus benchmark F1 = 0.9976 (TP=205, FP=1, FN=0) — unchanged

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Add OWASP mapping and baseline mutation hooks for enhanced security analysis

* feat: Introduce health module and enhance health score computation with calibration tests

* feat: Add expectations configuration and cleanup .gitignore for log files

* feat: Implement theme selection and enhance settings panel for triage sync

* feat: Suppress false positives for strcpy calls with literal sources in AST

* feat: Update analyse_function_ssa to return body CFG for accurate analysis

* feat: Add bug report and feature request templates for improved issue tracking

* feat: removed dev scripts

* feat: update README.md for clarity and consistency in fixture descriptions

* feat: removed dev docs

* feat: clean up error handling and UI elements for improved user experience

* feat: adjust button sizes in HeaderBar for better UI consistency

* feat: enhance taint analysis with additional context for sanitizer and taint findings

* cargo fmt

* prettier

* refactor: simplify conditional checks and improve code readability in AST and screenshot capture scripts

* feat: add script to frame PNG screenshots with brand gradient

* feat: add fuzzing support with new targets and CI workflows

* refactor: streamline match expressions and improve formatting in CLI and output handling

* feat: enhance configuration display with detailed output options

* feat: stage demo configuration for improved CLI screenshot output

* feat: expose merge_configs function for user-configurable settings

* refactor: simplify code structure and improve readability in config handling

* refactor: improve descriptions for vulnerability patterns in various languages

* feat: update MIT License section with additional usage details and copyright information

* feat: update screenshots

* refactor: update build process and paths for frontend assets

* feat: add cross-file taint fuzzing target and supporting dictionary

* refactor: clean up formatting and comments in fuzz configuration and example files

* refactor: remove outdated comments and clean up CI configuration files

* chore: update changelog dates and improve formatting in documentation

* refactor: update Cargo.toml and CI configuration for improved packaging and build process

* refactor: enhance quote-stripping logic to prevent panics and add regression tests

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eli Peter 2026-04-29 00:58:38 -04:00 committed by GitHub
parent 79c29b394d
commit 82f18184b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
348 changed files with 48731 additions and 2925 deletions

View file

@ -12,7 +12,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Banned functions (always dangerous) ────────────────────
Pattern {
id: "c.memory.gets",
description: "gets() — no bounds checking, always exploitable",
description: "gets() has no bounds checking and is always exploitable",
query: r#"(call_expression function: (identifier) @id (#eq? @id "gets")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -21,7 +21,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "c.memory.strcpy",
description: "strcpy() — no bounds checking on destination buffer",
description: "strcpy() does not bounds-check the destination buffer",
query: r#"(call_expression function: (identifier) @id (#eq? @id "strcpy")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -30,7 +30,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "c.memory.strcat",
description: "strcat() — no bounds checking on destination buffer",
description: "strcat() does not bounds-check the destination buffer",
query: r#"(call_expression function: (identifier) @id (#eq? @id "strcat")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -39,7 +39,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "c.memory.sprintf",
description: "sprintf() — no length limit on output buffer",
description: "sprintf() does not limit the output buffer length",
query: r#"(call_expression function: (identifier) @id (#eq? @id "sprintf")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -48,7 +48,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "c.memory.scanf_percent_s",
description: "scanf(\"%s\") unbounded string read",
description: "scanf(\"%s\") performs an unbounded string read",
query: r#"(call_expression
function: (identifier) @id (#eq? @id "scanf")
arguments: (argument_list
@ -62,7 +62,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Command execution ──────────────────────────────────────
Pattern {
id: "c.cmdi.system",
description: "system() — shell command execution",
description: "system() runs a shell command",
query: r#"(call_expression function: (identifier) @id (#eq? @id "system")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -71,7 +71,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "c.cmdi.popen",
description: "popen() — shell command execution with pipe",
description: "popen() runs a shell command and returns a pipe",
query: r#"(call_expression function: (identifier) @id (#eq? @id "popen")) @vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
@ -81,7 +81,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Format-string ──────────────────────────────────────────
Pattern {
id: "c.memory.printf_no_fmt",
description: "printf(var) — format-string vulnerability when first arg is not literal",
description: "printf(var) is a format-string vulnerability when the first arg is not a literal",
query: r#"(call_expression
function: (identifier) @id (#eq? @id "printf")
arguments: (argument_list

View file

@ -10,7 +10,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Banned C functions (inherited) ─────────────────────────
Pattern {
id: "cpp.memory.gets",
description: "gets() — no bounds checking, always exploitable",
description: "gets() has no bounds checking and is always exploitable",
query: r#"(call_expression function: (identifier) @id (#eq? @id "gets")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -19,7 +19,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "cpp.memory.strcpy",
description: "strcpy() — no bounds checking on destination buffer",
description: "strcpy() does not bounds-check the destination buffer",
query: r#"(call_expression function: (identifier) @id (#eq? @id "strcpy")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -28,7 +28,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "cpp.memory.strcat",
description: "strcat() — no bounds checking on destination buffer",
description: "strcat() does not bounds-check the destination buffer",
query: r#"(call_expression function: (identifier) @id (#eq? @id "strcat")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -37,7 +37,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "cpp.memory.sprintf",
description: "sprintf() — no length limit on output buffer",
description: "sprintf() does not limit the output buffer length",
query: r#"(call_expression function: (identifier) @id (#eq? @id "sprintf")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -47,7 +47,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Command execution ──────────────────────────────────────
Pattern {
id: "cpp.cmdi.system",
description: "system() — shell command execution",
description: "system() runs a shell command",
query: r#"(call_expression function: (identifier) @id (#eq? @id "system")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -56,7 +56,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "cpp.cmdi.popen",
description: "popen() — shell command execution",
description: "popen() runs a shell command",
query: r#"(call_expression function: (identifier) @id (#eq? @id "popen")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -67,7 +67,7 @@ pub const PATTERNS: &[Pattern] = &[
// C++ casts are parsed as call_expression with template_function
Pattern {
id: "cpp.memory.reinterpret_cast",
description: "reinterpret_cast type-punning cast",
description: "reinterpret_cast performs a type-punning cast",
query: r#"(call_expression
function: (template_function
name: (identifier) @n (#eq? @n "reinterpret_cast")))
@ -79,7 +79,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "cpp.memory.const_cast",
description: "const_cast removes const/volatile qualifier",
description: "const_cast removes the const/volatile qualifier",
query: r#"(call_expression
function: (template_function
name: (identifier) @n (#eq? @n "const_cast")))
@ -92,7 +92,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier B: Format-string (variable first arg) ─────────────────────
Pattern {
id: "cpp.memory.printf_no_fmt",
description: "printf(var) — format-string vulnerability when first arg is not literal",
description: "printf(var) is a format-string vulnerability when the first arg is not a literal",
query: r#"(call_expression
function: (identifier) @id (#eq? @id "printf")
arguments: (argument_list

View file

@ -10,7 +10,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Command execution ──────────────────────────────────────
Pattern {
id: "go.cmdi.exec_command",
description: "exec.Command() — arbitrary process execution",
description: "exec.Command() runs an arbitrary process",
query: r#"(call_expression
function: (selector_expression
field: (field_identifier) @f (#eq? @f "Command")))
@ -23,7 +23,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Unsafe pointer ─────────────────────────────────────────
Pattern {
id: "go.memory.unsafe_pointer",
description: "unsafe.Pointer bypasses Go type system",
description: "unsafe.Pointer bypasses the Go type system",
query: r#"(call_expression
function: (selector_expression
operand: (identifier) @pkg (#eq? @pkg "unsafe")
@ -37,7 +37,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: TLS misconfiguration ───────────────────────────────────
Pattern {
id: "go.transport.insecure_skip_verify",
description: "InsecureSkipVerify: true disables TLS certificate validation",
description: "InsecureSkipVerify: true disables TLS certificate validation",
query: r#"(keyed_element
(literal_element
(identifier) @k (#eq? @k "InsecureSkipVerify"))
@ -51,7 +51,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Weak crypto ────────────────────────────────────────────
Pattern {
id: "go.crypto.md5",
description: "md5.New() / md5.Sum() weak hash algorithm",
description: "md5.New() / md5.Sum() use a weak hash algorithm",
query: r#"(call_expression
function: (selector_expression
operand: (identifier) @pkg (#eq? @pkg "md5")))
@ -63,7 +63,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "go.crypto.sha1",
description: "sha1.New() / sha1.Sum() weak hash algorithm",
description: "sha1.New() / sha1.Sum() use a weak hash algorithm",
query: r#"(call_expression
function: (selector_expression
operand: (identifier) @pkg (#eq? @pkg "sha1")))
@ -106,7 +106,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Deserialization ────────────────────────────────────────
Pattern {
id: "go.deser.gob_decode",
description: "gob.NewDecoder Go binary deserialization",
description: "gob.NewDecoder performs Go binary deserialization",
query: r#"(call_expression
function: (selector_expression
operand: (identifier) @pkg (#eq? @pkg "gob")

View file

@ -11,7 +11,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Deserialization ────────────────────────────────────────
Pattern {
id: "java.deser.readobject",
description: "ObjectInputStream.readObject() unsafe deserialization",
description: "ObjectInputStream.readObject() performs unsafe deserialization",
// Match any .readObject() call — the method name is specific enough.
query: r#"(method_invocation
name: (identifier) @id (#eq? @id "readObject"))
@ -24,7 +24,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Command execution ──────────────────────────────────────
Pattern {
id: "java.cmdi.runtime_exec",
description: "Runtime.getRuntime().exec() — shell command execution",
description: "Runtime.getRuntime().exec() runs a shell command",
query: r#"(method_invocation
object: (method_invocation
name: (identifier) @n (#eq? @n "getRuntime"))
@ -38,7 +38,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Reflection ─────────────────────────────────────────────
Pattern {
id: "java.reflection.class_forname",
description: "Class.forName() dynamic class loading",
description: "Class.forName() performs dynamic class loading",
query: r#"(method_invocation
object: (identifier) @c (#eq? @c "Class")
name: (identifier) @id (#eq? @id "forName"))
@ -50,7 +50,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "java.reflection.method_invoke",
description: "Method.invoke() reflective method invocation",
description: "Method.invoke() is a reflective method invocation",
query: r#"(method_invocation
name: (identifier) @id (#eq? @id "invoke"))
@vuln"#,
@ -76,7 +76,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Weak crypto ────────────────────────────────────────────
Pattern {
id: "java.crypto.insecure_random",
description: "new Random() — java.util.Random is not cryptographically secure",
description: "new Random() (java.util.Random) is not cryptographically secure",
query: r#"(object_creation_expression
type: (type_identifier) @t (#eq? @t "Random"))
@vuln"#,
@ -87,7 +87,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "java.crypto.weak_digest",
description: "MessageDigest.getInstance(\"MD5\"/\"SHA1\") weak hash algorithm",
description: "MessageDigest.getInstance(\"MD5\"/\"SHA1\") uses a weak hash algorithm",
query: r#"(method_invocation
object: (identifier) @c (#eq? @c "MessageDigest")
name: (identifier) @id (#eq? @id "getInstance")
@ -102,7 +102,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: XSS (servlet) ──────────────────────────────────────────
Pattern {
id: "java.xss.getwriter_print",
description: "response.getWriter().print/println — direct output without encoding",
description: "response.getWriter().print/println writes output without encoding",
query: r#"(method_invocation
object: (method_invocation
name: (identifier) @gw (#eq? @gw "getWriter"))

View file

@ -12,7 +12,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Code execution ─────────────────────────────────────────
Pattern {
id: "js.code_exec.eval",
description: "eval() — dynamic code execution",
description: "eval() runs dynamic code",
query: r#"(call_expression
function: (identifier) @id (#eq? @id "eval"))
@vuln"#,
@ -23,7 +23,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.code_exec.new_function",
description: "new Function() constructor — eval equivalent",
description: "new Function() constructor is equivalent to eval",
query: r#"(new_expression
constructor: (identifier) @id (#eq? @id "Function"))
@vuln"#,
@ -34,7 +34,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.code_exec.settimeout_string",
description: "setTimeout/setInterval with string argument — implicit eval",
description: "setTimeout/setInterval with a string argument runs implicit eval",
query: r#"(call_expression
function: (identifier) @id (#match? @id "^(setTimeout|setInterval)$")
arguments: (arguments (string) @code))
@ -47,7 +47,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: XSS sinks ──────────────────────────────────────────────
Pattern {
id: "js.xss.document_write",
description: "document.write() XSS sink",
description: "document.write() is an XSS sink",
query: r#"(call_expression
function: (member_expression
object: (identifier) @obj (#eq? @obj "document")
@ -60,7 +60,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.xss.outer_html",
description: "Assignment to .outerHTML XSS sink",
description: "Assignment to .outerHTML is an XSS sink",
query: r#"(assignment_expression
left: (member_expression
property: (property_identifier) @prop (#eq? @prop "outerHTML")))
@ -72,7 +72,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.xss.insert_adjacent_html",
description: "insertAdjacentHTML() XSS sink",
description: "insertAdjacentHTML() is an XSS sink",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @prop (#eq? @prop "insertAdjacentHTML")))
@ -85,7 +85,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Prototype pollution ────────────────────────────────────
Pattern {
id: "js.prototype.proto_assignment",
description: "Assignment to __proto__ prototype pollution",
description: "Assignment to __proto__ causes prototype pollution",
query: r#"(assignment_expression
left: (member_expression
property: (property_identifier) @prop (#eq? @prop "__proto__")))
@ -97,7 +97,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.prototype.extend_object",
description: "Assignment to Object.prototype — prototype mutation",
description: "Assignment to Object.prototype mutates the prototype",
query: r#"(assignment_expression
left: (member_expression
object: (member_expression
@ -126,7 +126,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.crypto.weak_hash_import",
description: "Direct md5()/sha1() call — weak hash from imported package",
description: "Direct md5()/sha1() call uses a weak hash from an imported package",
query: r#"(call_expression
function: (identifier) @id (#match? @id "^(md5|sha1)$"))
@vuln"#,
@ -137,7 +137,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.crypto.math_random",
description: "Math.random() not cryptographically secure",
description: "Math.random() is not cryptographically secure",
query: r#"(call_expression
function: (member_expression
object: (identifier) @obj (#eq? @obj "Math")
@ -165,7 +165,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Open redirect ──────────────────────────────────────────
Pattern {
id: "js.xss.location_assign",
description: "Assignment to location/location.href — open redirect",
description: "Assignment to location/location.href is an open-redirect sink",
query: r#"(assignment_expression
left: (member_expression
object: (identifier) @obj (#match? @obj "^(window|location|document)$")
@ -207,7 +207,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Insecure session / cookie configuration ─────────────────
Pattern {
id: "js.config.insecure_session_httponly",
description: "Session cookie with httpOnly: false allows XSS-based session theft",
description: "Session cookie with httpOnly: false allows XSS-based session theft",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "httpOnly")
value: (false) @val)
@ -219,7 +219,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "js.config.insecure_session_secure",
description: "Session cookie with secure: false — cookie sent over plain HTTP",
description: "Session cookie with secure: false sends the cookie over plain HTTP",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "secure")
value: (false) @val)
@ -276,7 +276,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Verbose error response ────────────────────────────────
Pattern {
id: "js.config.verbose_error_response",
description: "Error object passed to response renderer — may leak stack traces to users",
description: "Error object passed to response renderer can leak stack traces to users",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @method
@ -295,7 +295,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier B: CORS dynamic origin reflection ────────────────────────
Pattern {
id: "js.config.cors_dynamic_origin",
description: "CORS Access-Control-Allow-Origin set to dynamic value — may reflect arbitrary origins",
description: "CORS Access-Control-Allow-Origin set to a dynamic value can reflect arbitrary origins",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @method (#eq? @method "setHeader"))

View file

@ -12,7 +12,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Code execution ─────────────────────────────────────────
Pattern {
id: "php.code_exec.eval",
description: "eval() — dynamic code execution",
description: "eval() runs dynamic code",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "eval"))
@vuln"#,
@ -23,7 +23,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "php.code_exec.create_function",
description: "create_function() deprecated eval-like constructor",
description: "create_function() is a deprecated eval-like constructor",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "create_function"))
@vuln"#,
@ -34,7 +34,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "php.code_exec.preg_replace_e",
description: "preg_replace with /e modifier — code execution via regex",
description: "preg_replace with /e modifier executes code via regex",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "preg_replace")
arguments: (arguments
@ -48,7 +48,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "php.code_exec.assert_string",
description: "assert() with string argument evaluates PHP code",
description: "assert() with a string argument evaluates PHP code",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "assert")
arguments: (arguments
@ -62,7 +62,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Command execution ──────────────────────────────────────
Pattern {
id: "php.cmdi.system",
description: "system/shell_exec/exec/passthru — shell command execution",
description: "system/shell_exec/exec/passthru runs a shell command",
query: r#"(function_call_expression
function: (name) @n (#match? @n "^(system|shell_exec|exec|passthru|proc_open|popen)$"))
@vuln"#,
@ -74,7 +74,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Deserialization ────────────────────────────────────────
Pattern {
id: "php.deser.unserialize",
description: "unserialize() PHP object injection",
description: "unserialize() enables PHP object injection",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "unserialize"))
@vuln"#,
@ -100,7 +100,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier B: Path traversal (include with variable) ─────────────────
Pattern {
id: "php.path.include_variable",
description: "include/require with variable path — file inclusion vulnerability",
description: "include/require with a variable path is a file-inclusion vulnerability",
query: r#"(include_expression (variable_name)) @vuln"#,
severity: Severity::High,
tier: PatternTier::B,
@ -110,7 +110,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Crypto ─────────────────────────────────────────────────
Pattern {
id: "php.crypto.md5",
description: "md5() weak hash function",
description: "md5() is a weak hash function",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "md5"))
@vuln"#,
@ -121,7 +121,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "php.crypto.sha1",
description: "sha1() weak hash function",
description: "sha1() is a weak hash function",
query: r#"(function_call_expression
function: (name) @n (#eq? @n "sha1"))
@vuln"#,
@ -132,7 +132,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "php.crypto.rand",
description: "rand()/mt_rand() not cryptographically secure",
description: "rand()/mt_rand() is not cryptographically secure",
query: r#"(function_call_expression
function: (name) @n (#match? @n "^(rand|mt_rand)$"))
@vuln"#,

View file

@ -11,7 +11,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Code execution ─────────────────────────────────────────
Pattern {
id: "py.code_exec.eval",
description: "eval() — dynamic code execution",
description: "eval() runs dynamic code",
query: r#"(call function: (identifier) @id (#eq? @id "eval")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -20,7 +20,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "py.code_exec.exec",
description: "exec() — dynamic code execution",
description: "exec() runs dynamic code",
query: r#"(call function: (identifier) @id (#eq? @id "exec")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -29,7 +29,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "py.code_exec.compile",
description: "compile() with exec/eval mode — code compilation from string",
description: "compile() with exec/eval mode compiles code from a string",
query: r#"(call function: (identifier) @id (#eq? @id "compile")) @vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
@ -39,7 +39,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Command execution ──────────────────────────────────────
Pattern {
id: "py.cmdi.os_system",
description: "os.system() — shell command execution",
description: "os.system() runs a shell command",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "os")
@ -52,7 +52,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "py.cmdi.os_popen",
description: "os.popen() — shell command execution",
description: "os.popen() runs a shell command",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "os")
@ -83,7 +83,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Deserialization ────────────────────────────────────────
Pattern {
id: "py.deser.pickle_loads",
description: "pickle.loads/load — arbitrary object deserialization",
description: "pickle.loads/load deserializes arbitrary objects",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "pickle")
@ -96,7 +96,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "py.deser.yaml_load",
description: "yaml.load() without SafeLoader — arbitrary object instantiation",
description: "yaml.load() without SafeLoader instantiates arbitrary objects",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "yaml")
@ -109,7 +109,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "py.deser.shelve_open",
description: "shelve.open() pickle-backed deserialization",
description: "shelve.open() performs pickle-backed deserialization",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "shelve")
@ -123,7 +123,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier B: SQL injection (format/concat heuristic) ────────────────
Pattern {
id: "py.sqli.execute_format",
description: "cursor.execute with string concatenation — SQL injection risk",
description: "cursor.execute with string concatenation risks SQL injection",
query: r#"(call
function: (attribute
attribute: (identifier) @fn (#eq? @fn "execute"))
@ -138,7 +138,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Weak crypto ────────────────────────────────────────────
Pattern {
id: "py.crypto.md5",
description: "hashlib.md5() weak hash algorithm",
description: "hashlib.md5() uses a weak hash algorithm",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "hashlib")
@ -151,7 +151,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "py.crypto.sha1",
description: "hashlib.sha1() weak hash algorithm",
description: "hashlib.sha1() uses a weak hash algorithm",
query: r#"(call
function: (attribute
object: (identifier) @pkg (#eq? @pkg "hashlib")
@ -165,7 +165,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Template injection ─────────────────────────────────────
Pattern {
id: "py.xss.jinja_from_string",
description: "jinja2.Template from string — potential template injection",
description: "jinja2.Template from string risks template injection",
query: r#"(call
function: (attribute
attribute: (identifier) @fn (#eq? @fn "from_string")))

View file

@ -11,7 +11,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Code execution ─────────────────────────────────────────
Pattern {
id: "rb.code_exec.eval",
description: "Kernel#eval — dynamic code execution",
description: "Kernel#eval runs dynamic code",
query: r#"(call (identifier) @id (#eq? @id "eval")) @vuln"#,
severity: Severity::High,
tier: PatternTier::A,
@ -20,7 +20,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rb.code_exec.instance_eval",
description: "instance_eval evaluates string in object context",
description: "instance_eval evaluates a string in object context",
query: r#"(call
method: (identifier) @id (#eq? @id "instance_eval"))
@vuln"#,
@ -31,7 +31,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rb.code_exec.class_eval",
description: "class_eval / module_eval evaluates string in class context",
description: "class_eval / module_eval evaluates a string in class context",
query: r#"(call
method: (identifier) @id (#match? @id "^(class_eval|module_eval)$"))
@vuln"#,
@ -53,7 +53,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Shell execution ─────────────────────────────────────────
Pattern {
id: "rb.cmdi.system_interp",
description: "system/exec call — command execution risk",
description: "system/exec call runs a command",
query: r#"(call
method: (identifier) @m (#match? @m "^(system|exec)$"))
@vuln"#,
@ -65,7 +65,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Deserialization ────────────────────────────────────────
Pattern {
id: "rb.deser.yaml_load",
description: "YAML.load — arbitrary object deserialization (use safe_load instead)",
description: "YAML.load deserializes arbitrary objects (use safe_load instead)",
query: r#"(call
receiver: (constant) @recv (#match? @recv "^(YAML|Psych)$")
method: (identifier) @m (#eq? @m "load"))
@ -77,7 +77,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rb.deser.marshal_load",
description: "Marshal.load — arbitrary Ruby object deserialization",
description: "Marshal.load deserializes arbitrary Ruby objects",
query: r#"(call
receiver: (constant) @recv (#eq? @recv "Marshal")
method: (identifier) @m (#eq? @m "load"))
@ -90,7 +90,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Reflection ─────────────────────────────────────────────
Pattern {
id: "rb.reflection.send_dynamic",
description: "send() with non-symbol argument — arbitrary method dispatch",
description: "send() with a non-symbol argument is arbitrary method dispatch",
query: r#"(call
method: (identifier) @m (#eq? @m "send")
arguments: (argument_list
@ -103,7 +103,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rb.reflection.constantize",
description: "constantize / safe_constantize dynamic class resolution",
description: "constantize / safe_constantize performs dynamic class resolution",
query: r#"(call
method: (identifier) @m (#match? @m "^(constantize|safe_constantize)$"))
@vuln"#,
@ -115,7 +115,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: SSRF ───────────────────────────────────────────────────
Pattern {
id: "rb.ssrf.open_uri",
description: "Kernel#open with HTTP URL — SSRF via open-uri",
description: "Kernel#open with an HTTP URL is an SSRF sink via open-uri",
query: r#"(call
method: (identifier) @m (#eq? @m "open")
arguments: (argument_list
@ -129,7 +129,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Crypto ─────────────────────────────────────────────────
Pattern {
id: "rb.crypto.md5",
description: "Digest::MD5 weak hash algorithm",
description: "Digest::MD5 is a weak hash algorithm",
query: r#"(scope_resolution
name: (constant) @c (#eq? @c "MD5"))
@vuln"#,

View file

@ -11,7 +11,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Memory Safety (unsafe) ─────────────────────────────────
Pattern {
id: "rs.memory.transmute",
description: "std::mem::transmute unchecked type reinterpretation",
description: "std::mem::transmute performs unchecked type reinterpretation",
query: r#"(call_expression
function: (scoped_identifier
path: (identifier) @p (#eq? @p "mem")
@ -24,7 +24,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.memory.copy_nonoverlapping",
description: "ptr::copy_nonoverlapping raw pointer memcpy",
description: "ptr::copy_nonoverlapping is a raw pointer memcpy",
query: r#"(call_expression
function: (scoped_identifier
path: (identifier) @p (#eq? @p "ptr")
@ -37,7 +37,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.memory.get_unchecked",
description: "get_unchecked / get_unchecked_mut unchecked indexing",
description: "get_unchecked / get_unchecked_mut performs unchecked indexing",
query: r#"(call_expression
function: (field_expression
field: (field_identifier) @m
@ -50,7 +50,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.memory.mem_zeroed",
description: "std::mem::zeroed — zero-initialised memory may be UB for non-POD types",
description: "std::mem::zeroed is UB for non-POD types since the zero pattern may not be a valid value",
query: r#"(call_expression
function: (scoped_identifier
path: (identifier) @p (#eq? @p "mem")
@ -63,7 +63,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.memory.ptr_read",
description: "ptr::read / ptr::read_volatile — raw pointer dereference",
description: "ptr::read / ptr::read_volatile dereferences a raw pointer",
query: r#"(call_expression
function: (scoped_identifier
path: (identifier) @p (#eq? @p "ptr")
@ -77,7 +77,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Code quality / robustness ──────────────────────────────
Pattern {
id: "rs.quality.unsafe_block",
description: "unsafe block manual memory safety obligation",
description: "unsafe block carries a manual memory safety obligation",
query: "(unsafe_block) @vuln",
severity: Severity::Medium,
tier: PatternTier::A,
@ -98,7 +98,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.quality.unwrap",
description: ".unwrap() panics on None/Err",
description: ".unwrap() panics on None/Err",
query: r#"(call_expression
function: (field_expression
field: (field_identifier) @name (#eq? @name "unwrap")))
@ -110,7 +110,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.quality.expect",
description: ".expect() panics on None/Err",
description: ".expect() panics on None/Err",
query: r#"(call_expression
function: (field_expression
field: (field_identifier) @name (#eq? @name "expect")))
@ -144,7 +144,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Narrowing cast ─────────────────────────────────────────
Pattern {
id: "rs.memory.narrow_cast",
description: "`as` cast to 8/16-bit integer — possible truncation",
description: "`as` cast to 8/16-bit integer can truncate",
query: r#"(type_cast_expression
type: (primitive_type) @to
(#match? @to "^(u8|i8|u16|i16)$"))
@ -156,7 +156,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "rs.memory.mem_forget",
description: "std::mem::forget — may leak resources",
description: "std::mem::forget can leak resources",
query: r#"(call_expression
function: (scoped_identifier
path: (identifier) @p (#eq? @p "mem")

View file

@ -10,7 +10,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Code execution ─────────────────────────────────────────
Pattern {
id: "ts.code_exec.eval",
description: "eval() — dynamic code execution",
description: "eval() runs dynamic code",
query: r#"(call_expression
function: (identifier) @id (#eq? @id "eval"))
@vuln"#,
@ -21,7 +21,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.code_exec.new_function",
description: "new Function() constructor — eval equivalent",
description: "new Function() constructor is equivalent to eval",
query: r#"(new_expression
constructor: (identifier) @id (#eq? @id "Function"))
@vuln"#,
@ -32,7 +32,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.code_exec.settimeout_string",
description: "setTimeout/setInterval with string argument — implicit eval",
description: "setTimeout/setInterval with a string argument runs implicit eval",
query: r#"(call_expression
function: (identifier) @id (#match? @id "^(setTimeout|setInterval)$")
arguments: (arguments (string) @code))
@ -45,7 +45,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: XSS sinks ──────────────────────────────────────────────
Pattern {
id: "ts.xss.document_write",
description: "document.write() XSS sink",
description: "document.write() is an XSS sink",
query: r#"(call_expression
function: (member_expression
object: (identifier) @obj (#eq? @obj "document")
@ -58,7 +58,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.xss.outer_html",
description: "Assignment to .outerHTML XSS sink",
description: "Assignment to .outerHTML is an XSS sink",
query: r#"(assignment_expression
left: (member_expression
property: (property_identifier) @prop (#eq? @prop "outerHTML")))
@ -70,7 +70,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.xss.insert_adjacent_html",
description: "insertAdjacentHTML() XSS sink",
description: "insertAdjacentHTML() is an XSS sink",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @prop (#eq? @prop "insertAdjacentHTML")))
@ -97,7 +97,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.crypto.weak_hash_import",
description: "Direct md5()/sha1() call — weak hash from imported package",
description: "Direct md5()/sha1() call uses a weak hash from an imported package",
query: r#"(call_expression
function: (identifier) @id (#match? @id "^(md5|sha1)$"))
@vuln"#,
@ -108,7 +108,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.crypto.math_random",
description: "Math.random() not cryptographically secure",
description: "Math.random() is not cryptographically secure",
query: r#"(call_expression
function: (member_expression
object: (identifier) @obj (#eq? @obj "Math")
@ -136,7 +136,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: TypeScript-specific type-safety escapes ────────────────
Pattern {
id: "ts.quality.any_annotation",
description: "Type annotation of `any` disables type checking",
description: "Type annotation of `any` disables type checking",
query: r#"(type_annotation (predefined_type) @t (#eq? @t "any")) @vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
@ -145,7 +145,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.quality.as_any",
description: "Type assertion `as any` type-safety escape hatch",
description: "Type assertion `as any` is a type-safety escape hatch",
query: r#"(as_expression (predefined_type) @t (#eq? @t "any")) @vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
@ -155,7 +155,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Prototype pollution ────────────────────────────────────
Pattern {
id: "ts.prototype.proto_assignment",
description: "Assignment to __proto__ prototype pollution",
description: "Assignment to __proto__ causes prototype pollution",
query: r#"(assignment_expression
left: (member_expression
property: (property_identifier) @prop (#eq? @prop "__proto__")))
@ -168,7 +168,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Open redirect ──────────────────────────────────────────
Pattern {
id: "ts.xss.location_assign",
description: "Assignment to location/location.href — open redirect",
description: "Assignment to location/location.href is an open-redirect sink",
query: r#"(assignment_expression
left: (member_expression
object: (identifier) @obj (#match? @obj "^(window|location|document)$")
@ -196,7 +196,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Insecure session / cookie configuration ─────────────────
Pattern {
id: "ts.config.insecure_session_httponly",
description: "Session cookie with httpOnly: false allows XSS-based session theft",
description: "Session cookie with httpOnly: false allows XSS-based session theft",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "httpOnly")
value: (false) @val)
@ -208,7 +208,7 @@ pub const PATTERNS: &[Pattern] = &[
},
Pattern {
id: "ts.config.insecure_session_secure",
description: "Session cookie with secure: false — cookie sent over plain HTTP",
description: "Session cookie with secure: false sends the cookie over plain HTTP",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "secure")
value: (false) @val)
@ -265,7 +265,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier A: Verbose error response ────────────────────────────────
Pattern {
id: "ts.config.verbose_error_response",
description: "Error object passed to response renderer — may leak stack traces to users",
description: "Error object passed to response renderer can leak stack traces to users",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @method
@ -284,7 +284,7 @@ pub const PATTERNS: &[Pattern] = &[
// ── Tier B: CORS dynamic origin reflection ────────────────────────
Pattern {
id: "ts.config.cors_dynamic_origin",
description: "CORS Access-Control-Allow-Origin set to dynamic value — may reflect arbitrary origins",
description: "CORS Access-Control-Allow-Origin set to a dynamic value can reflect arbitrary origins",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @method (#eq? @method "setHeader"))