use crate::evidence::Confidence;
use crate::patterns::{Pattern, PatternCategory, PatternTier, Severity};
pub const PATTERNS: &[Pattern] = &[
Pattern {
id: "ts.code_exec.eval",
description: "eval() runs dynamic code",
query: r#"(call_expression
function: (identifier) @id (#eq? @id "eval"))
@vuln"#,
severity: Severity::High,
tier: PatternTier::A,
category: PatternCategory::CodeExec,
confidence: Confidence::High,
},
Pattern {
id: "ts.code_exec.new_function",
description: "new Function() constructor is equivalent to eval",
query: r#"(new_expression
constructor: (identifier) @id (#eq? @id "Function"))
@vuln"#,
severity: Severity::High,
tier: PatternTier::A,
category: PatternCategory::CodeExec,
confidence: Confidence::High,
},
Pattern {
id: "ts.code_exec.settimeout_string",
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))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::CodeExec,
confidence: Confidence::High,
},
Pattern {
id: "ts.xss.document_write",
description: "document.write() is an XSS sink",
query: r#"(call_expression
function: (member_expression
object: (identifier) @obj (#eq? @obj "document")
property: (property_identifier) @prop (#match? @prop "^(write|writeln)$")))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Xss,
confidence: Confidence::High,
},
Pattern {
id: "ts.xss.outer_html",
description: "Assignment to .outerHTML is an XSS sink",
query: r#"(assignment_expression
left: (member_expression
property: (property_identifier) @prop (#eq? @prop "outerHTML")))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Xss,
confidence: Confidence::High,
},
Pattern {
id: "ts.xss.insert_adjacent_html",
description: "insertAdjacentHTML() is an XSS sink",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @prop (#eq? @prop "insertAdjacentHTML")))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Xss,
confidence: Confidence::High,
},
Pattern {
id: "ts.crypto.weak_hash",
description: "crypto.createHash with weak algorithm (md5/sha1)",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @prop (#eq? @prop "createHash"))
arguments: (arguments
(string) @alg (#match? @alg "\"(md5|sha1)\"")))
@vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
category: PatternCategory::Crypto,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.crypto.weak_hash_import",
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"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Crypto,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.crypto.math_random",
description: "Math.random() is not cryptographically secure",
query: r#"(call_expression
function: (member_expression
object: (identifier) @obj (#eq? @obj "Math")
property: (property_identifier) @prop (#eq? @prop "random")))
@vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
category: PatternCategory::Crypto,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.secrets.hardcoded_secret",
description: "Hardcoded secret/password/API key in source code",
query: r#"(pair
key: (property_identifier) @key
(#match? @key "^(secret|password|api_key|apiKey|apiSecret|api_secret|SESSION_SECRET|secretKey|secret_key|privateKey|private_key)$")
value: (string) @val)
@vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
category: PatternCategory::Secrets,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.quality.any_annotation",
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,
category: PatternCategory::CodeQuality,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.quality.as_any",
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,
category: PatternCategory::CodeQuality,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.prototype.proto_assignment",
description: "Assignment to __proto__ causes prototype pollution",
query: r#"(assignment_expression
left: (member_expression
property: (property_identifier) @prop (#eq? @prop "__proto__")))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Prototype,
confidence: Confidence::High,
},
Pattern {
id: "ts.xss.location_assign",
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)$")
property: (property_identifier) @prop (#match? @prop "^(location|href)$")))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Xss,
confidence: Confidence::High,
},
Pattern {
id: "ts.xss.cookie_write",
description: "Write to document.cookie",
query: r#"(assignment_expression
left: (member_expression
object: (identifier) @obj (#eq? @obj "document")
property: (property_identifier) @prop (#eq? @prop "cookie")))
@vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
category: PatternCategory::Xss,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.config.insecure_session_httponly",
description: "Session cookie with httpOnly: false allows XSS-based session theft",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "httpOnly")
value: (false) @val)
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::InsecureConfig,
confidence: Confidence::High,
},
Pattern {
id: "ts.config.insecure_session_secure",
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)
@vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
category: PatternCategory::InsecureConfig,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.config.insecure_session_samesite",
description: "sameSite: \"none\" allows cross-origin cookie sending, increasing CSRF risk",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "sameSite")
value: (string) @val (#match? @val "^[\"']none[\"']$"))
@vuln"#,
severity: Severity::Low,
tier: PatternTier::A,
category: PatternCategory::InsecureConfig,
confidence: Confidence::High,
},
Pattern {
id: "ts.config.reject_unauthorized",
description: "TLS certificate verification disabled via rejectUnauthorized: false",
query: r#"(pair
key: (property_identifier) @key (#eq? @key "rejectUnauthorized")
value: (false) @val)
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::InsecureConfig,
confidence: Confidence::High,
},
Pattern {
id: "ts.secrets.fallback_secret",
description: "Environment variable with secret-like name has hardcoded fallback value",
query: r#"(binary_expression
left: (member_expression
object: (member_expression
object: (identifier) @proc (#eq? @proc "process")
property: (property_identifier) @env (#eq? @env "env"))
property: (property_identifier) @key
(#match? @key "(?i)(secret|password|key|token)"))
operator: "||"
right: (string) @fallback (#match? @fallback "[^\"']"))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::Secrets,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.config.verbose_error_response",
description: "Error object passed to response renderer can leak stack traces to users",
query: r#"(call_expression
function: (member_expression
property: (property_identifier) @method
(#match? @method "^(render|send|json)$"))
arguments: (arguments
(_)
(object
(shorthand_property_identifier) @prop
(#eq? @prop "error"))))
@vuln"#,
severity: Severity::Medium,
tier: PatternTier::A,
category: PatternCategory::InsecureConfig,
confidence: Confidence::Medium,
},
Pattern {
id: "ts.config.cors_dynamic_origin",
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"))
arguments: (arguments
(string) @header_name (#match? @header_name "Access-Control-Allow-Origin")
. (identifier) @value))
@vuln"#,
severity: Severity::High,
tier: PatternTier::A,
category: PatternCategory::InsecureConfig,
confidence: Confidence::Medium,
},
];