[[matcher]]
id = "dangerous-html"
cwe = 79
title = "Dangerous HTML sink"
sink_shape = "member-assign"
callee_patterns = ["*.innerHTML", "*.outerHTML"]
arg_index = 0
evidence_template = "Non-literal value assigned to {callee}. Candidate for verification: confirm the value is not attacker-controlled, or is sanitized, before it reaches the DOM."
[[matcher]]
id = "dangerous-html"
cwe = 79
title = "Dangerous HTML sink"
sink_shape = "member-call"
callee_patterns = ["*.insertAdjacentHTML"]
arg_index = 1
evidence_template = "Non-literal HTML passed to {callee}(). Candidate for verification: confirm the markup is not attacker-controlled or is sanitized."
[[matcher]]
id = "dangerous-html"
cwe = 79
title = "Dangerous HTML sink"
sink_shape = "jsx-attr"
callee_patterns = ["dangerouslySetInnerHTML"]
arg_index = 0
evidence_template = "Non-literal value bound to {callee}. Candidate for verification: confirm the HTML is sanitized (e.g. via DOMPurify) before render."
[[matcher]]
id = "template-escape-bypass"
cwe = 79
title = "Template escape bypass sink"
sink_shape = "member-call"
callee_patterns = ["*.SafeString"]
arg_index = 0
evidence_template = "Non-literal value wrapped by {callee}() (marks the string as pre-escaped). Candidate for verification: confirm the value is sanitized before bypassing the template engine's HTML escaping."
[[matcher]]
id = "command-injection"
cwe = 78
title = "OS command injection sink"
sink_shape = "member-call"
callee_patterns = ["child_process.exec", "child_process.execSync", "child_process.spawn", "child_process.spawnSync"]
arg_index = 0
import_provenance = "node:child_process"
evidence_template = "Non-literal command passed to {callee}(). Candidate for verification: confirm the command/args are not attacker-controlled (prefer the array-arg spawn form)."
[[matcher]]
id = "command-injection"
cwe = 78
title = "OS command injection sink"
sink_shape = "call"
callee_patterns = ["exec", "execSync", "spawn", "spawnSync"]
arg_index = 0
import_provenance = "node:child_process"
evidence_template = "Non-literal command passed to {callee}(). Candidate for verification: confirm the command/args are not attacker-controlled."
[[matcher]]
id = "code-injection"
cwe = 94
title = "Code injection sink"
sink_shape = "call"
callee_patterns = ["eval"]
arg_index = 0
evidence_template = "Non-literal value passed to {callee}(). Candidate for verification: confirm a string of code is never executed from untrusted input."
[[matcher]]
id = "code-injection"
cwe = 94
title = "Code injection sink"
sink_shape = "member-call"
callee_patterns = ["vm.runInNewContext", "vm.runInThisContext", "vm.runInContext"]
arg_index = 0
import_provenance = "node:vm"
evidence_template = "Non-literal code passed to {callee}(). Candidate for verification: confirm the script source is trusted."
[[matcher]]
id = "code-injection"
cwe = 95
title = "String-code timer sink"
sink_shape = "call"
callee_patterns = ["setTimeout", "setInterval"]
arg_index = 0
arg_kinds = ["literal"]
evidence_template = "String code passed to {callee}(). Candidate for verification: prefer a function callback over evaluating a string."
[[matcher]]
id = "code-injection"
cwe = 95
title = "Function constructor sink"
sink_shape = "new-expression"
callee_patterns = ["Function"]
arg_index = 0
arg_kinds = ["literal"]
evidence_template = "String body passed to new {callee}(). Candidate for verification: confirm generated code cannot be influenced by attacker input."
[[matcher]]
id = "code-injection"
cwe = 95
title = "Function constructor sink"
sink_shape = "new-expression"
callee_patterns = ["Function"]
arg_index = 0
evidence_template = "Non-literal value passed to new {callee}(). Candidate for verification: confirm generated code cannot be influenced by attacker input."
[[matcher]]
id = "dynamic-regex"
cwe = 1333
title = "Dynamic regular expression sink"
sink_shape = "call"
callee_patterns = ["RegExp"]
arg_index = 0
evidence_template = "Non-literal pattern passed to {callee}(). Candidate for verification: confirm attacker input cannot control the regular expression."
[[matcher]]
id = "dynamic-regex"
cwe = 1333
title = "Dynamic regular expression sink"
sink_shape = "new-expression"
callee_patterns = ["RegExp"]
arg_index = 0
evidence_template = "Non-literal pattern passed to new {callee}(). Candidate for verification: confirm attacker input cannot control the regular expression."
[[matcher]]
id = "redos-regex"
cwe = 1333
title = "ReDoS regex sink"
sink_shape = "member-call"
callee_patterns = ["RegExp.redos"]
arg_index = 0
requires_source = true
evidence_template = "Risky regex pattern fragment `{regex}` is applied to untrusted input. Candidate for verification: confirm the pattern cannot trigger catastrophic backtracking on attacker-controlled strings."
[[matcher]]
id = "resource-amplification"
cwe = 400
title = "Resource amplification sink"
sink_shape = "call"
callee_patterns = ["Array"]
arg_index = 0
requires_source = true
evidence_template = "Untrusted size reaches {callee}(). Candidate for verification: clamp the size before allocating or expanding work."
[[matcher]]
id = "resource-amplification"
cwe = 400
title = "Resource amplification sink"
sink_shape = "new-expression"
callee_patterns = ["Array"]
arg_index = 0
requires_source = true
evidence_template = "Untrusted size reaches new {callee}(). Candidate for verification: clamp the size before allocating or expanding work."
[[matcher]]
id = "resource-amplification"
cwe = 400
title = "Resource amplification sink"
sink_shape = "member-call"
callee_patterns = ["Buffer.alloc", "Buffer.allocUnsafe", "Buffer.allocUnsafeSlow", "*.repeat", "*.padStart", "*.padEnd"]
arg_index = 0
requires_source = true
evidence_template = "Untrusted size reaches {callee}(). Candidate for verification: clamp the size before allocating or expanding work."
[[matcher]]
id = "dynamic-module-load"
cwe = 95
title = "Dynamic module load sink"
sink_shape = "call"
callee_patterns = ["require"]
arg_index = 0
evidence_template = "Non-literal module specifier passed to {callee}(). Candidate for verification: confirm attacker input cannot select the module path or package name."
[[matcher]]
id = "sql-injection"
cwe = 89
title = "SQL injection sink"
sink_shape = "member-call"
callee_patterns = ["*.query", "*.execute"]
arg_index = 0
arg_kinds = ["concat", "template-with-subst"]
evidence_template = "Non-literal SQL ({callee}() called with a string concatenation or interpolated template). Candidate for verification: confirm the query uses parameterized bindings, not string building, for untrusted input."
[[matcher]]
id = "sql-injection"
cwe = 89
title = "SQL injection sink"
sink_shape = "member-call"
callee_patterns = [
"sql.raw",
"*.sql.raw",
"*.$queryRawUnsafe",
"*.$executeRawUnsafe",
"*.whereRaw",
"*.havingRaw",
"*.orderByRaw",
"knex.raw",
"sequelize.literal",
"Sequelize.literal",
]
arg_index = 0
evidence_template = "Non-literal value passed to {callee}(). Candidate for verification: raw SQL escape hatches bypass parameterization; confirm the fragment is not attacker-controlled."
[[matcher]]
id = "ssrf"
cwe = 918
title = "Server-side request forgery sink"
sink_shape = "call"
callee_patterns = ["fetch", "got", "ky", "needle", "request"]
arg_index = 0
evidence_template = "Non-literal URL passed to {callee}(). Candidate for verification: confirm the destination host is not attacker-controlled (allowlist outbound targets)."
[[matcher]]
id = "ssrf"
cwe = 918
title = "Server-side request forgery sink"
sink_shape = "member-call"
callee_patterns = ["axios.get", "axios.post", "http.request", "https.request", "superagent.get", "undici.request"]
arg_index = 0
evidence_template = "Non-literal URL passed to {callee}(). Candidate for verification: confirm the destination is not attacker-controlled."
[[matcher]]
id = "ssrf"
cwe = 918
title = "Cloud metadata request sink"
sink_shape = "call"
callee_patterns = ["fetch", "got", "ky", "needle", "request"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["169.254.169.254", "metadata.google.internal"]
evidence_template = "Literal cloud metadata URL passed to {callee}(). Candidate for verification: confirm this request cannot expose instance credentials or metadata."
[[matcher]]
id = "ssrf"
cwe = 918
title = "Cloud metadata request sink"
sink_shape = "member-call"
callee_patterns = ["axios.get", "axios.post", "http.request", "https.request", "undici.request"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["169.254.169.254", "metadata.google.internal"]
evidence_template = "Literal cloud metadata URL passed to {callee}(). Candidate for verification: confirm this request cannot expose instance credentials or metadata."
[[matcher]]
id = "secret-to-network"
cwe = 201
title = "Secret reaches a network request"
sink_shape = "call"
callee_patterns = ["fetch", "got", "ky", "needle", "request"]
arg_index = 1
requires_source = true
requires_source_kinds = ["process-env", "import-meta-env"]
evidence_template = "A non-public env secret reaches the body/options of {callee}(). Candidate for verification: confirm this credential is intended for this destination (an auth header sent to the credential's own provider is normal); review only if the destination is untrusted, attacker-influenced, or not the credential's provider."
[[matcher]]
id = "secret-to-network"
cwe = 201
title = "Secret reaches a network request"
sink_shape = "member-call"
callee_patterns = ["axios.post", "axios.put", "axios.patch", "axios.request", "got.post", "http.request", "https.request", "undici.request"]
arg_index = 1
requires_source = true
requires_source_kinds = ["process-env", "import-meta-env"]
evidence_template = "A non-public env secret reaches the body/options of {callee}(). Candidate for verification: confirm this credential is intended for this destination (an auth header sent to the credential's own provider is normal); review only if the destination is untrusted or not the credential's provider."
[[matcher]]
id = "path-traversal"
cwe = 22
title = "Path traversal sink"
sink_shape = "member-call"
callee_patterns = ["path.join", "path.resolve"]
arg_index = 0
import_provenance = "node:path"
evidence_template = "Non-literal path component passed to {callee}(). Candidate for verification: confirm the input cannot escape the intended directory (reject `..`)."
[[matcher]]
id = "path-traversal"
cwe = 22
title = "File-system path traversal sink"
sink_shape = "member-call"
callee_patterns = ["fs.readFile", "fs.readFileSync", "fs.writeFile", "fs.createReadStream", "fs.unlink", "fs.rename"]
arg_index = 0
import_provenance = "node:fs"
evidence_template = "Non-literal file-system path passed to {callee}(). Candidate for verification: confirm the input cannot escape the intended directory (reject `..`)."
[[matcher]]
id = "path-traversal"
cwe = 22
title = "File-system path traversal sink"
sink_shape = "member-call"
callee_patterns = ["fs.rename"]
arg_index = 1
import_provenance = "node:fs"
evidence_template = "Non-literal file-system path passed to {callee}(). Candidate for verification: confirm the destination cannot escape the intended directory (reject `..`)."
[[matcher]]
id = "header-injection"
cwe = 113
title = "HTTP response header injection sink"
sink_shape = "member-call"
callee_patterns = ["*.setHeader"]
arg_index = 1
evidence_template = "Non-literal header value passed to {callee}(). Candidate for verification: confirm CR/LF and untrusted header content are rejected before writing the response."
[[matcher]]
id = "header-injection"
cwe = 113
title = "HTTP response header injection sink"
sink_shape = "member-call"
callee_patterns = ["*.writeHead"]
arg_index = 1
evidence_template = "Non-literal headers object passed to {callee}(). Candidate for verification: confirm attacker input cannot inject response header names or values."
[[matcher]]
id = "open-redirect"
cwe = 601
title = "Open redirect sink"
sink_shape = "member-call"
callee_patterns = ["res.redirect", "*.redirect"]
arg_index = 0
evidence_template = "Non-literal redirect target passed to {callee}(). Candidate for verification: confirm the target is a relative path or allowlisted host."
[[matcher]]
id = "open-redirect"
cwe = 601
title = "DOM navigation sink"
sink_shape = "member-assign"
callee_patterns = ["location.href", "*.location.href"]
arg_index = 0
evidence_template = "Non-literal navigation target assigned to {callee}. Candidate for verification: confirm the target is a relative path or allowlisted host and cannot be a javascript URL."
[[matcher]]
id = "open-redirect"
cwe = 601
title = "DOM navigation sink"
sink_shape = "member-call"
callee_patterns = ["location.assign", "location.replace", "*.location.assign", "*.location.replace", "window.open"]
arg_index = 0
evidence_template = "Non-literal navigation target passed to {callee}(). Candidate for verification: confirm the target is a relative path or allowlisted host and cannot be a javascript URL."
[[matcher]]
id = "postmessage-wildcard-origin"
cwe = 346
title = "Wildcard postMessage target origin"
sink_shape = "call"
callee_patterns = ["postMessage"]
arg_index = 1
arg_kinds = ["literal"]
literal_values = ["*"]
evidence_template = "Wildcard target origin passed to {callee}(). Candidate for verification: use a specific trusted origin instead of `*`."
[[matcher]]
id = "postmessage-wildcard-origin"
cwe = 346
title = "Wildcard postMessage target origin"
sink_shape = "member-call"
callee_patterns = ["*.postMessage"]
arg_index = 1
arg_kinds = ["literal"]
literal_values = ["*"]
evidence_template = "Wildcard target origin passed to {callee}(). Candidate for verification: use a specific trusted origin instead of `*`."
[[matcher]]
id = "tls-validation-disabled"
cwe = 295
title = "TLS validation disabled"
sink_shape = "member-call"
callee_patterns = ["https.request", "https.get"]
arg_index = 1
arg_kinds = ["object"]
import_provenance = "node:https"
object_properties = [{ key = "rejectUnauthorized", boolean = false }]
evidence_template = "TLS options passed to {callee}() disable certificate validation. Candidate for verification: remove `rejectUnauthorized: false` so certificate validation remains enabled."
[[matcher]]
id = "tls-validation-disabled"
cwe = 295
title = "TLS validation disabled"
sink_shape = "call"
callee_patterns = ["request", "get"]
arg_index = 1
arg_kinds = ["object"]
import_provenance = "node:https"
object_properties = [{ key = "rejectUnauthorized", boolean = false }]
evidence_template = "TLS options passed to {callee}() disable certificate validation. Candidate for verification: remove `rejectUnauthorized: false` so certificate validation remains enabled."
[[matcher]]
id = "tls-validation-disabled"
cwe = 295
title = "TLS validation disabled"
sink_shape = "member-call"
callee_patterns = ["tls.connect"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "node:tls"
object_properties = [{ key = "rejectUnauthorized", boolean = false }]
evidence_template = "TLS options passed to {callee}() disable certificate validation. Candidate for verification: remove `rejectUnauthorized: false` so certificate validation remains enabled."
[[matcher]]
id = "tls-validation-disabled"
cwe = 295
title = "TLS validation disabled"
sink_shape = "call"
callee_patterns = ["connect"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "node:tls"
object_properties = [{ key = "rejectUnauthorized", boolean = false }]
evidence_template = "TLS options passed to {callee}() disable certificate validation. Candidate for verification: remove `rejectUnauthorized: false` so certificate validation remains enabled."
[[matcher]]
id = "tls-validation-disabled"
cwe = 295
title = "TLS validation disabled"
sink_shape = "new-expression"
callee_patterns = ["https.Agent", "Agent"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "node:https"
object_properties = [{ key = "rejectUnauthorized", boolean = false }]
evidence_template = "TLS agent options passed to new {callee}() disable certificate validation. Candidate for verification: remove `rejectUnauthorized: false` so certificate validation remains enabled."
[[matcher]]
id = "tls-validation-disabled"
cwe = 295
title = "TLS validation disabled"
sink_shape = "member-assign"
callee_patterns = ["process.env.NODE_TLS_REJECT_UNAUTHORIZED"]
arg_index = 0
arg_kinds = ["literal"]
literal_values = ["0"]
evidence_template = "NODE_TLS_REJECT_UNAUTHORIZED is set to `0`, disabling TLS certificate validation for Node HTTPS clients. Candidate for verification: remove the assignment or set it to `1`."
[[matcher]]
id = "cleartext-transport"
cwe = 319
title = "Cleartext transport URL"
sink_shape = "new-expression"
callee_patterns = ["WebSocket"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["ws://"]
evidence_template = "Cleartext WebSocket URL passed to new {callee}(). Candidate for verification: use `wss://` unless this is intentionally confined to a trusted local network."
[[matcher]]
id = "cleartext-transport"
cwe = 319
title = "Cleartext transport URL"
sink_shape = "call"
callee_patterns = ["fetch", "got", "ky", "needle", "request"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["http://", "ftp://"]
evidence_template = "Cleartext URL passed to {callee}(). Candidate for verification: use HTTPS or another encrypted transport unless this is intentionally confined to a trusted local network."
[[matcher]]
id = "cleartext-transport"
cwe = 319
title = "Cleartext transport URL"
sink_shape = "member-call"
callee_patterns = ["axios.get", "axios.post", "http.request", "http.get", "superagent.get", "undici.request"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["http://", "ftp://"]
evidence_template = "Cleartext URL passed to {callee}(). Candidate for verification: use HTTPS or another encrypted transport unless this is intentionally confined to a trusted local network."
[[matcher]]
id = "electron-unsafe-webpreferences"
cwe = 1188
title = "Unsafe Electron BrowserWindow preferences"
sink_shape = "new-expression"
callee_patterns = ["BrowserWindow", "electron.BrowserWindow"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "electron"
enabler = "electron"
object_properties = [{ key = "webPreferences.nodeIntegration", boolean = true }]
evidence_template = "Electron BrowserWindow enables nodeIntegration. Candidate for verification: keep Node integration disabled in renderer windows unless the window is fully trusted."
[[matcher]]
id = "electron-unsafe-webpreferences"
cwe = 1188
title = "Unsafe Electron BrowserWindow preferences"
sink_shape = "new-expression"
callee_patterns = ["BrowserWindow", "electron.BrowserWindow"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "electron"
enabler = "electron"
object_properties = [{ key = "webPreferences.webSecurity", boolean = false }]
evidence_template = "Electron BrowserWindow disables webSecurity. Candidate for verification: keep web security enabled unless the window is fully trusted and isolated."
[[matcher]]
id = "electron-unsafe-webpreferences"
cwe = 1188
title = "Unsafe Electron BrowserWindow preferences"
sink_shape = "new-expression"
callee_patterns = ["BrowserWindow", "electron.BrowserWindow"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "electron"
enabler = "electron"
object_properties = [{ key = "webPreferences.contextIsolation", boolean = false }]
evidence_template = "Electron BrowserWindow disables contextIsolation. Candidate for verification: keep context isolation enabled for renderer windows."
[[matcher]]
id = "world-writable-permission"
cwe = 732
title = "World-writable chmod mode"
sink_shape = "member-call"
callee_patterns = ["fs.chmod", "fs.chmodSync", "fs.promises.chmod"]
arg_index = 1
arg_kinds = ["literal"]
literal_integers = [511]
import_provenance = "node:fs"
evidence_template = "World-writable mode passed to {callee}(). Candidate for verification: avoid granting write access to other users."
[[matcher]]
id = "world-writable-permission"
cwe = 732
title = "World-writable chmod mode"
sink_shape = "call"
callee_patterns = ["chmod", "chmodSync"]
arg_index = 1
arg_kinds = ["literal"]
literal_integers = [511]
import_provenance = "node:fs"
evidence_template = "World-writable mode passed to {callee}(). Candidate for verification: avoid granting write access to other users."
[[matcher]]
id = "insecure-temp-file"
cwe = 377
title = "Predictable temporary file path"
sink_shape = "member-call"
callee_patterns = ["fs.writeFile", "fs.writeFileSync", "fs.appendFile", "fs.appendFileSync", "fs.createWriteStream", "fs.promises.writeFile", "fs.promises.appendFile"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["/tmp/", "/var/tmp/"]
import_provenance = "node:fs"
evidence_template = "Literal temporary-file path passed to {callee}(). Candidate for verification: prefer an unpredictable path from `fs.mkdtemp` or `os.tmpdir()` plus a random suffix."
[[matcher]]
id = "insecure-temp-file"
cwe = 377
title = "Predictable temporary file path"
sink_shape = "call"
callee_patterns = ["writeFile", "writeFileSync", "appendFile", "appendFileSync", "createWriteStream"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["/tmp/", "/var/tmp/"]
import_provenance = "node:fs"
evidence_template = "Literal temporary-file path passed to {callee}(). Candidate for verification: prefer an unpredictable path from `fs.mkdtemp` or `os.tmpdir()` plus a random suffix."
[[matcher]]
id = "mysql-multiple-statements"
cwe = 89
title = "MySQL multiple statements enabled"
sink_shape = "member-call"
callee_patterns = ["mysql.createConnection", "mysql.createPool", "mysql2.createConnection", "mysql2.createPool"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "mysql"
enabler = "mysql"
object_properties = [{ key = "multipleStatements", boolean = true }]
evidence_template = "MySQL connection options enable multipleStatements. Candidate for verification: keep multiple statements disabled unless every query path is strictly parameterized."
[[matcher]]
id = "mysql-multiple-statements"
cwe = 89
title = "MySQL multiple statements enabled"
sink_shape = "call"
callee_patterns = ["createConnection", "createPool"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "mysql"
enabler = "mysql"
object_properties = [{ key = "multipleStatements", boolean = true }]
evidence_template = "MySQL connection options enable multipleStatements. Candidate for verification: keep multiple statements disabled unless every query path is strictly parameterized."
[[matcher]]
id = "mysql-multiple-statements"
cwe = 89
title = "MySQL multiple statements enabled"
sink_shape = "member-call"
callee_patterns = ["mysql.createConnection", "mysql.createPool", "mysql2.createConnection", "mysql2.createPool"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "mysql2"
enabler = "mysql2"
object_properties = [{ key = "multipleStatements", boolean = true }]
evidence_template = "MySQL connection options enable multipleStatements. Candidate for verification: keep multiple statements disabled unless every query path is strictly parameterized."
[[matcher]]
id = "mysql-multiple-statements"
cwe = 89
title = "MySQL multiple statements enabled"
sink_shape = "call"
callee_patterns = ["createConnection", "createPool"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "mysql2"
enabler = "mysql2"
object_properties = [{ key = "multipleStatements", boolean = true }]
evidence_template = "MySQL connection options enable multipleStatements. Candidate for verification: keep multiple statements disabled unless every query path is strictly parameterized."
[[matcher]]
id = "permissive-cors"
cwe = 942
title = "Permissive CORS policy"
sink_shape = "call"
callee_patterns = ["cors"]
arg_index = 0
arg_kinds = ["object"]
import_provenance = "cors"
object_properties = [{ key = "origin", string = "*" }, { key = "credentials", boolean = true }]
evidence_template = "CORS configured with wildcard origin and credentials. Candidate for verification: credentials require a specific trusted origin."
[[matcher]]
id = "insecure-cookie"
cwe = 614
title = "Insecure cookie options"
sink_shape = "member-call"
callee_patterns = ["*.cookie"]
arg_index = 2
arg_kinds = ["object"]
enabler = "express"
object_missing_or_false = ["httpOnly", "secure"]
evidence_template = "Cookie options omit or disable httpOnly/secure. Candidate for verification: set both flags unless this cookie is intentionally readable or non-secure."
[[matcher]]
id = "mass-assignment"
cwe = 915
title = "Mass assignment sink"
sink_shape = "member-call"
callee_patterns = ["Object.assign"]
arg_index = 1
arg_kinds = ["other"]
requires_source = true
evidence_template = "Source-backed object passed to {callee}(). Candidate for verification: confirm attacker-controlled properties cannot overwrite sensitive fields or prototypes."
[[matcher]]
id = "weak-crypto"
cwe = 327
title = "Runtime-selectable crypto algorithm"
sink_shape = "member-call"
callee_patterns = ["crypto.createHash", "crypto.createCipheriv"]
arg_index = 0
import_provenance = "node:crypto"
evidence_template = "Runtime-selectable algorithm passed to {callee}(). Candidate for verification: confirm a weak algorithm (md5/sha1/des/rc4) cannot be selected at runtime."
[[matcher]]
id = "weak-crypto"
cwe = 327
title = "Weak crypto algorithm"
sink_shape = "member-call"
callee_patterns = ["crypto.createHash", "crypto.createCipher", "crypto.createDecipher", "crypto.createCipheriv", "crypto.createDecipheriv"]
arg_index = 0
arg_kinds = ["literal"]
literal_values = ["md5", "sha1", "des", "rc4", "des-ede3-cbc"]
import_provenance = "node:crypto"
evidence_template = "Weak literal algorithm passed to {callee}(). Candidate for verification: use a modern hash or cipher such as SHA-256 or AES-GCM."
[[matcher]]
id = "weak-crypto"
cwe = 327
title = "Weak crypto algorithm"
sink_shape = "member-call"
callee_patterns = ["crypto.createCipher", "crypto.createDecipher", "crypto.createCipheriv", "crypto.createDecipheriv"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["-ecb"]
import_provenance = "node:crypto"
evidence_template = "ECB-mode cipher algorithm passed to {callee}(). Candidate for verification: use an authenticated mode such as AES-GCM or ChaCha20-Poly1305."
[[matcher]]
id = "weak-crypto"
cwe = 327
title = "Weak crypto algorithm"
sink_shape = "call"
callee_patterns = ["createHash", "createCipher", "createDecipher", "createCipheriv", "createDecipheriv"]
arg_index = 0
arg_kinds = ["literal"]
literal_values = ["md5", "sha1", "des", "rc4", "des-ede3-cbc"]
import_provenance = "node:crypto"
evidence_template = "Weak literal algorithm passed to {callee}(). Candidate for verification: use a modern hash or cipher such as SHA-256 or AES-GCM."
[[matcher]]
id = "weak-crypto"
cwe = 327
title = "Weak crypto algorithm"
sink_shape = "call"
callee_patterns = ["createCipher", "createDecipher", "createCipheriv", "createDecipheriv"]
arg_index = 0
arg_kinds = ["literal"]
literal_contains = ["-ecb"]
import_provenance = "node:crypto"
evidence_template = "ECB-mode cipher algorithm passed to {callee}(). Candidate for verification: use an authenticated mode such as AES-GCM or ChaCha20-Poly1305."
[[matcher]]
id = "insecure-randomness"
cwe = 338
title = "Insecure randomness sink"
sink_shape = "member-call"
callee_patterns = ["crypto.pseudoRandomBytes"]
arg_index = 0
import_provenance = "node:crypto"
evidence_template = "Non-literal length passed to {callee}(). Candidate for verification: pseudoRandomBytes is NOT cryptographically secure; use crypto.randomBytes for tokens, salts, or keys."
[[matcher]]
id = "insecure-randomness"
cwe = 338
title = "Insecure randomness sink"
sink_shape = "member-call"
callee_patterns = ["Math.random"]
arg_index = 0
arg_kinds = ["no-arg"]
context_keywords = ["token", "secret", "session", "jwt", "auth", "csrf", "nonce", "salt", "password", "credential"]
evidence_template = "Math.random() feeds a security-sensitive context. Candidate for verification: use cryptographic randomness for tokens, salts, secrets, and credentials."
[[matcher]]
id = "jwt-alg-none"
cwe = 347
title = "JWT alg none"
sink_shape = "member-call"
callee_patterns = ["*.sign"]
arg_index = 2
arg_kinds = ["object"]
import_provenance = "jsonwebtoken"
object_properties = [{ key = "algorithm", string = "none" }]
evidence_template = "JWT signed with algorithm `none`. Candidate for verification: require a real signing algorithm and reject unsigned tokens."
[[matcher]]
id = "jwt-alg-none"
cwe = 347
title = "JWT alg none"
sink_shape = "call"
callee_patterns = ["sign"]
arg_index = 2
arg_kinds = ["object"]
import_provenance = "jsonwebtoken"
object_properties = [{ key = "algorithm", string = "none" }]
evidence_template = "JWT signed with algorithm `none`. Candidate for verification: require a real signing algorithm and reject unsigned tokens."
[[matcher]]
id = "jwt-verify-missing-algorithms"
cwe = 347
title = "JWT verify missing algorithms allowlist"
sink_shape = "member-call"
callee_patterns = ["*.verify"]
arg_index = 2
arg_kinds = ["object"]
import_provenance = "jsonwebtoken"
object_missing = ["algorithms"]
evidence_template = "JWT verified without an explicit `algorithms` allowlist. Candidate for verification: pass `{ algorithms: [...] }` matching the expected signing algorithm family."
[[matcher]]
id = "jwt-verify-missing-algorithms"
cwe = 347
title = "JWT verify missing algorithms allowlist"
sink_shape = "call"
callee_patterns = ["verify"]
arg_index = 2
arg_kinds = ["object"]
import_provenance = "jsonwebtoken"
object_missing = ["algorithms"]
evidence_template = "JWT verified without an explicit `algorithms` allowlist. Candidate for verification: pass `{ algorithms: [...] }` matching the expected signing algorithm family."
[[matcher]]
id = "deprecated-cipher"
cwe = 327
title = "Deprecated cipher constructor"
sink_shape = "member-call"
callee_patterns = ["crypto.createCipher", "crypto.createDecipher"]
arg_index = 1
import_provenance = "node:crypto"
evidence_template = "Deprecated {callee}() (single-pass MD5 key derivation, no IV). Candidate for verification: migrate to createCipheriv with a random IV and a strong KDF (scrypt/PBKDF2)."
[[matcher]]
id = "unsafe-buffer-alloc"
cwe = 1188
title = "Unsafe Buffer allocation sink"
sink_shape = "member-call"
callee_patterns = ["Buffer.allocUnsafe", "Buffer.allocUnsafeSlow"]
arg_index = 0
evidence_template = "Non-literal length passed to {callee}() (uninitialized memory). Candidate for verification: use Buffer.alloc (zero-filled) or fully overwrite the buffer before it is read or sent."
[[matcher]]
id = "unsafe-deserialization"
cwe = 502
title = "Unsafe deserialization sink"
sink_shape = "call"
callee_patterns = ["unserialize"]
arg_index = 0
import_provenance = "node-serialize"
evidence_template = "Non-literal input passed to {callee}(). Candidate for verification: node-serialize unserialize executes embedded functions; confirm the input is trusted."
[[matcher]]
id = "unsafe-deserialization"
cwe = 502
title = "Unsafe deserialization sink"
sink_shape = "member-call"
callee_patterns = ["yaml.load", "jsyaml.load"]
arg_index = 0
import_provenance = "js-yaml"
evidence_template = "js-yaml load() without a safe schema. Candidate for verification: use load with the default safe schema (js-yaml >=4) or an explicit SAFE_SCHEMA."
[[matcher]]
id = "angular-trusted-html"
cwe = 79
title = "Angular bypassSecurityTrust sink"
sink_shape = "member-call"
callee_patterns = [
"*.bypassSecurityTrustHtml",
"*.bypassSecurityTrustScript",
"*.bypassSecurityTrustStyle",
"*.bypassSecurityTrustUrl",
"*.bypassSecurityTrustResourceUrl",
]
arg_index = 0
enabler = "@angular/platform-browser"
evidence_template = "Non-literal value passed to Angular's {callee}(). Candidate for verification: bypassSecurityTrust* disables Angular's built-in sanitization; confirm the value is not attacker-controlled."
[[matcher]]
id = "nextjs-open-redirect"
cwe = 601
title = "Next.js open redirect sink"
sink_shape = "call"
callee_patterns = ["redirect", "permanentRedirect"]
arg_index = 0
import_provenance = "next/navigation"
enabler = "next"
evidence_template = "Non-literal target passed to Next.js {callee}(). Candidate for verification: confirm the redirect target is a relative path or allowlisted host, not attacker-controlled."
[[matcher]]
id = "dom-document-write"
cwe = 79
title = "DOM document.write sink"
sink_shape = "member-call"
callee_patterns = ["document.write", "document.writeln"]
arg_index = 0
evidence_template = "Non-literal value passed to {callee}(). Candidate for verification: confirm the markup is not attacker-controlled or is sanitized (prefer DOM construction over document.write)."
[[matcher]]
id = "jquery-html"
cwe = 79
title = "jQuery .html() sink"
sink_shape = "member-call"
callee_patterns = ["*.html"]
arg_index = 0
enabler = "jquery"
evidence_template = "Non-literal value passed to jQuery {callee}(). Candidate for verification: jQuery .html() parses its argument as markup; confirm the value is not attacker-controlled or is sanitized."
[[matcher]]
id = "route-send-file"
cwe = 22
title = "Route file-send path traversal sink"
sink_shape = "member-call"
callee_patterns = ["*.sendFile"]
arg_index = 0
enabler = "express"
evidence_template = "Non-literal path passed to {callee}(). Candidate for verification: confirm the served path cannot escape the intended directory (reject `..`)."
[[matcher]]
id = "route-send-file"
cwe = 22
title = "Route file-send path traversal sink"
sink_shape = "member-call"
callee_patterns = ["*.sendFile"]
arg_index = 0
enabler = "@fastify/"
evidence_template = "Non-literal path passed to {callee}(). Candidate for verification: confirm the served path cannot escape the intended directory (reject `..`)."
[[matcher]]
id = "route-send-file"
cwe = 22
title = "Route file-send path traversal sink"
sink_shape = "member-call"
callee_patterns = ["*.sendFile"]
arg_index = 0
enabler = "hono"
evidence_template = "Non-literal path passed to {callee}(). Candidate for verification: confirm the served path cannot escape the intended directory (reject `..`)."
[[matcher]]
id = "webview-injection"
cwe = 94
title = "WebView injected-script sink"
sink_shape = "member-call"
callee_patterns = ["*.injectJavaScript"]
arg_index = 0
enabler = "react-native-webview"
evidence_template = "Non-literal script passed to {callee}() (runs in the embedded WebView). Candidate for verification: confirm the script body is not attacker-controlled."
[[matcher]]
id = "webview-injection"
cwe = 94
title = "WebView injected-script sink"
sink_shape = "jsx-attr"
callee_patterns = ["injectedJavaScript"]
arg_index = 0
enabler = "react-native-webview"
evidence_template = "Non-literal script bound to {callee} (runs in the embedded WebView). Candidate for verification: confirm the script body is not attacker-controlled."
[[source]]
id = "http-request-input"
title = "HTTP request input"
path_patterns = ["*.query", "*.params", "*.body"]
receiver_allowlist = ["req", "request", "ctx", "context", "event"]
[[source]]
id = "http-request-input"
title = "HTTP request input"
path_patterns = ["*.searchParams"]
[[source]]
id = "framework-handler-input"
title = "Framework handler input"
enabler = "express"
path_patterns = ["framework.request"]
[[source]]
id = "framework-handler-input"
title = "Framework handler input"
enabler = "fastify"
path_patterns = ["framework.request"]
[[source]]
id = "framework-handler-input"
title = "Framework handler input"
enabler = "koa"
path_patterns = ["framework.request"]
[[source]]
id = "framework-handler-input"
title = "Framework handler input"
enabler = "hono"
path_patterns = ["framework.request"]
[[source]]
id = "next-handler-input"
title = "Next.js handler input"
enabler = "next"
path_patterns = ["next.request", "next.form-data"]
[[source]]
id = "queue-job-input"
title = "Queue job input"
enabler = "bullmq"
path_patterns = ["queue.job"]
[[source]]
id = "queue-job-input"
title = "Queue job input"
enabler = "bull"
path_patterns = ["queue.job"]
[[source]]
id = "mcp-tool-input"
title = "MCP tool input"
enabler = "@modelcontextprotocol/sdk"
path_patterns = ["mcp.tool-input"]
[[source]]
id = "graphql-resolver-args"
title = "GraphQL resolver args"
enabler = "graphql"
path_patterns = ["graphql.args"]
[[source]]
id = "graphql-resolver-args"
title = "GraphQL resolver args"
enabler = "@apollo/server"
path_patterns = ["graphql.args"]
[[source]]
id = "graphql-resolver-args"
title = "GraphQL resolver args"
enabler = "apollo-server"
path_patterns = ["graphql.args"]
[[source]]
id = "graphql-resolver-args"
title = "GraphQL resolver args"
enabler = "apollo-server-express"
path_patterns = ["graphql.args"]
[[source]]
id = "graphql-resolver-args"
title = "GraphQL resolver args"
enabler = "graphql-yoga"
path_patterns = ["graphql.args"]
[[source]]
id = "graphql-resolver-args"
title = "GraphQL resolver args"
enabler = "@graphql-yoga/node"
path_patterns = ["graphql.args"]
[[source]]
id = "trpc-procedure-input"
title = "tRPC procedure input"
enabler = "@trpc/server"
path_patterns = ["trpc.input"]
[[source]]
id = "webhook-raw-body"
title = "Webhook raw body"
path_patterns = ["req.rawBody", "request.rawBody", "ctx.req.rawBody", "*.rawBody"]
[[source]]
id = "process-argv"
title = "Process arguments"
path_patterns = ["process.argv", "*.argv"]
[[source]]
id = "process-env"
title = "Environment secret"
path_patterns = ["process.env"]
[[source]]
id = "import-meta-env"
title = "Environment secret (Vite)"
path_patterns = ["import.meta.env"]
[[source]]
id = "message-event-data"
title = "Message-event data"
path_patterns = ["*.data"]
[[source]]
id = "location-input"
title = "Browser location input"
path_patterns = ["*.search", "*.hash", "location.href", "*.location.href"]
[[source]]
id = "dom-xss-source"
title = "Browser DOM input"
path_patterns = ["document.referrer", "window.name", "document.cookie"]
[[matcher]]
id = "prototype-pollution"
cwe = 1321
title = "Prototype pollution sink"
sink_shape = "member-assign"
callee_patterns = ["*.__proto__"]
arg_index = 0
evidence_template = "Non-literal value assigned to {callee} (a direct prototype write). Candidate for verification: confirm the right-hand value and any key are not attacker-controlled."
[[matcher]]
id = "prototype-pollution"
cwe = 1321
title = "Prototype pollution sink"
sink_shape = "call"
callee_patterns = ["merge", "mergeWith", "defaultsDeep", "setWith"]
arg_index = 1
arg_kinds = ["other", "call"]
evidence_template = "Non-literal source passed to {callee}() (a recursive merge). Candidate for verification: confirm the merged source cannot carry `__proto__` / `constructor` / `prototype` keys from attacker input."
[[matcher]]
id = "prototype-pollution"
cwe = 1321
title = "Prototype pollution sink"
sink_shape = "member-call"
callee_patterns = ["*.merge", "*.mergeWith", "*.defaultsDeep", "*.setWith"]
arg_index = 1
arg_kinds = ["other", "call"]
evidence_template = "Non-literal source passed to {callee}() (a recursive merge). Candidate for verification: confirm the merged source cannot carry `__proto__` / `constructor` / `prototype` keys from attacker input."
[[matcher]]
id = "zip-slip"
cwe = 22
title = "Archive path-traversal (zip-slip) sink"
sink_shape = "member-call"
callee_patterns = ["tar.x", "tar.extract", "*.extractAllTo", "*.extractEntryTo"]
arg_index = 0
arg_kinds = ["other", "concat", "template-with-subst"]
evidence_template = "Non-literal destination/entry passed to {callee}() (archive extraction). Candidate for verification: confirm archive entry names cannot escape the target directory (reject `..`), guarding against zip-slip."
[[matcher]]
id = "nosql-injection"
cwe = 943
title = "NoSQL injection sink"
sink_shape = "member-call"
callee_patterns = ["*.findOne", "*.findOneAndUpdate", "*.updateOne", "*.updateMany", "*.deleteOne", "*.deleteMany"]
arg_index = 0
arg_kinds = ["other"]
evidence_template = "Non-literal query passed to {callee}() (a whole filter object passed through). Candidate for verification: confirm user input cannot inject query operators (`$where`, `$gt`, `$ne`); cast/validate the field types before querying."
[[matcher]]
id = "ssti"
cwe = 1336
title = "Server-side template injection sink"
sink_shape = "member-call"
callee_patterns = ["handlebars.compile", "eta.render", "eta.compile", "pug.compile", "ejs.render", "nunjucks.renderString", "nunjucks.compile"]
arg_index = 0
arg_kinds = ["template-with-subst", "concat", "call", "other"]
evidence_template = "Non-literal template source passed to {callee}(). Candidate for verification: confirm the template body is not attacker-controlled (SSTI executes template directives server-side)."
[[matcher]]
id = "xxe"
cwe = 611
title = "XML external entity (XXE) sink"
sink_shape = "member-call"
callee_patterns = ["libxml.parseXml", "libxml.parseXmlString", "*.parseXmlString", "*.parseStringPromise"]
arg_index = 0
evidence_template = "Non-literal XML document passed to {callee}(). Candidate for verification: confirm the parser disables external-entity / DTD expansion (no `noent`), guarding against XXE and entity-expansion attacks."
[[matcher]]
id = "secret-pii-log"
cwe = 532
title = "Secret or PII logged"
sink_shape = "member-call"
callee_patterns = [
"console.log",
"console.error",
"console.warn",
"console.info",
"console.debug",
"logger.log",
"logger.error",
"logger.warn",
"logger.info",
"logger.debug",
"log.log",
"log.error",
"log.warn",
"log.info",
"log.debug",
"*.logger.log",
"*.logger.error",
"*.logger.warn",
"*.logger.info",
"*.logger.debug",
"*.log.log",
"*.log.error",
"*.log.warn",
"*.log.info",
"*.log.debug",
]
arg_index = 0
requires_source = true
evidence_template = "Source-backed value passed to {callee}(). Candidate for verification: confirm no secret or PII reaches logs, observability pipelines, or telemetry."
[[matcher]]
id = "xpath-injection"
cwe = 643
title = "XPath injection sink"
sink_shape = "member-call"
callee_patterns = ["xpath.select", "xpath.select1"]
arg_index = 0
evidence_template = "Non-literal XPath expression passed to {callee}(). Candidate for verification: confirm user input cannot alter the query (bind variables / validate the expression)."