{ "version": "v1", "timestamp": 1776539423236, "ruleHash": "e3b0c44298fc1c14", "queries": [ { "id": "await-in-loop", "name": "Await in Loop", "severity": "warning", "language": "typescript", "message": "Await in loop — sequential execution is slow, use Promise.all()", "query": " (for_in_statement\n body: (statement_block\n (expression_statement\n (await_expression) @AWAIT)))\n (for_statement\n body: (statement_block\n (expression_statement\n (await_expression) @AWAIT)))\n (while_statement\n body: (statement_block\n (expression_statement\n (await_expression) @AWAIT)))", "metavars": [ "AWAIT" ], "defect_class": "injection", "inline_tier": "blocking" }, { "id": "console-statement", "name": "Console Statement", "severity": "warning", "language": "typescript", "message": "{{METHOD}} — remove debug statements before committing", "query": " (call_expression\n function: (member_expression\n object: (identifier) @OBJ (#eq? @OBJ \"console\")\n property: (property_identifier) @METHOD (#not-eq? @METHOD \"dbg\"))\n arguments: (arguments) @ARGS)\n\n# Skip matches inside test blocks — no-console-in-tests handles that case", "metavars": [ "OBJ", "METHOD", "ARGS" ], "post_filter": "not_in_test_block", "defect_class": "safety", "inline_tier": "warning" }, { "id": "constructor-super", "name": "Missing super() call in derived class constructor", "severity": "error", "language": "typescript", "message": "Constructor of derived class must call super() before accessing 'this'", "query": " (class_declaration\n (class_heritage\n (extends_clause) @EXTENDS)\n body: (class_body\n (method_definition\n name: (property_identifier) @CONSTRUCTOR\n (#eq? @CONSTRUCTOR \"constructor\")\n body: (statement_block) @BODY)))", "metavars": [ "EXTENDS", "CONSTRUCTOR", "BODY" ], "post_filter": "no_super_call", "post_filter_params": "{}", "defect_class": "correctness", "inline_tier": "blocking" }, { "id": "debugger-statement", "name": "Debugger Statement", "severity": "error", "language": "typescript", "message": "Debugger statement — remove before committing", "query": " (debugger_statement) @DEBUGGER", "metavars": [ "DEBUGGER" ], "defect_class": "safety", "inline_tier": "blocking" }, { "id": "deep-nesting", "name": "Deep Nesting", "severity": "warning", "language": "typescript", "message": "Deep nesting (3+ levels) — consider early returns or extract functions", "query": " [\n ;; Pattern 1: if inside if inside if\n (statement_block\n (if_statement\n consequence: (statement_block\n (if_statement\n consequence: (statement_block\n (if_statement) @IF_NESTED)))))\n\n ;; Pattern 2: for inside if inside if\n (statement_block\n (if_statement\n consequence: (statement_block\n (if_statement\n consequence: (statement_block\n (for_statement) @FOR_NESTED)))))\n\n ;; Pattern 3: while inside if inside if\n (statement_block\n (if_statement\n consequence: (statement_block\n (if_statement\n consequence: (statement_block\n (while_statement) @WHILE_NESTED)))))\n\n ;; Pattern 4: try inside if inside if\n (statement_block\n (if_statement\n consequence: (statement_block\n (if_statement\n consequence: (statement_block\n (try_statement) @TRY_NESTED)))))\n\n ;; Pattern 5: if inside for inside if\n (statement_block\n (if_statement\n consequence: (statement_block\n (for_statement\n body: (statement_block\n (if_statement) @IF_IN_FOR)))))\n\n ;; Pattern 6: if inside while inside if\n (statement_block\n (if_statement\n consequence: (statement_block\n (while_statement\n body: (statement_block\n (if_statement) @IF_IN_WHILE)))))\n\n ;; Pattern 7: for inside for inside for\n (statement_block\n (for_statement\n body: (statement_block\n (for_statement\n body: (statement_block\n (for_statement) @FOR_NESTED)))))\n ]", "metavars": [ "IF_NESTED", "FOR_NESTED", "WHILE_NESTED", "TRY_NESTED", "IF_IN_FOR", "IF_IN_WHILE" ], "defect_class": "safety", "inline_tier": "review" }, { "id": "deep-promise-chain", "name": "Deep Promise Chain (4+ levels)", "severity": "warning", "language": "typescript", "message": "Promise chain {{M1}} → {{M2}} → {{M3}} → {{M4}} — consider async/await", "query": " (call_expression\n function: (member_expression\n object: (call_expression\n function: (member_expression\n object: (call_expression\n function: (member_expression\n object: (call_expression\n function: (member_expression\n property: (property_identifier) @M1)\n arguments: (arguments))\n property: (property_identifier) @M2)\n arguments: (arguments))\n property: (property_identifier) @M3)\n arguments: (arguments))\n property: (property_identifier) @M4)\n arguments: (arguments))\n (#match? @M1 \"^(then|catch|finally)$\")\n (#match? @M2 \"^(then|catch|finally)$\")\n (#match? @M3 \"^(then|catch|finally)$\")\n (#match? @M4 \"^(then|catch|finally)$\")", "metavars": [ "M1", "M2", "M3", "M4" ], "defect_class": "async-misuse", "inline_tier": "warning" }, { "id": "empty-catch", "name": "Empty Catch Block", "severity": "error", "language": "typescript", "message": "Empty catch block — properly handle or log the error", "query": " (catch_clause\n (identifier) @ERR\n (statement_block) @BODY)\n\n# Post-filter: Check if body is effectively empty (ignoring comments)", "metavars": [ "ERR", "BODY" ], "post_filter": "empty_body", "defect_class": "silent-error", "inline_tier": "blocking" }, { "id": "no-eval", "name": "Eval Usage", "severity": "error", "language": "typescript", "message": "eval() detected — security risk, never use eval", "query": " (call_expression\n function: (identifier) @FUNC\n (#eq? @FUNC \"eval\")\n arguments: (arguments) @ARGS)", "metavars": [ "FUNC", "ARGS" ], "defect_class": "injection", "inline_tier": "blocking" }, { "id": "hardcoded-secrets", "name": "Hardcoded Secret", "severity": "error", "language": "typescript", "message": "Hardcoded secret in variable assignment — use environment variables", "query": " [\n (lexical_declaration\n (variable_declarator\n name: (identifier) @VARNAME\n value: (string)))\n (expression_statement\n (assignment_expression\n left: (identifier) @VARNAME\n right: (string)))\n ]", "metavars": [ "VARNAME" ], "post_filter": "check_secret_pattern", "defect_class": "secrets", "inline_tier": "blocking" }, { "id": "long-parameter-list", "name": "Long Parameter List", "severity": "warning", "language": "typescript", "message": "Function has {{PARAM_COUNT}} parameters — use object pattern", "query": " (function_declaration\n name: (identifier) @NAME\n parameters: (formal_parameters) @PARAMS\n body: (statement_block) @BODY)", "metavars": [ "NAME", "PARAMS", "BODY" ], "post_filter": "count_params", "post_filter_params": "", "defect_class": "safety", "inline_tier": "review" }, { "id": "mixed-async-styles", "name": "Mixed Async/Await and Promise Chains", "severity": "warning", "language": "typescript", "message": "Mixed async/await + promise chains — use consistent async style", "query": " (function_declaration\n (async_modifier)\n body: (statement_block) @BODY)\n\n# Post-filter: Check if body contains both await and .then()", "metavars": [ "BODY" ], "post_filter": "has_mixed_async", "defect_class": "async-misuse", "inline_tier": "warning" }, { "id": "nested-ternary", "name": "Nested Ternary", "severity": "warning", "language": "typescript", "message": "Nested ternary — use if/else or early returns for clarity", "query": " (ternary_expression\n consequence: (ternary_expression) @NESTED)\n (ternary_expression\n alternative: (ternary_expression) @NESTED)", "metavars": [ "NESTED" ], "defect_class": "safety", "inline_tier": "review" }, { "id": "no-console-in-tests", "name": "Console Statement in Test", "severity": "warning", "language": "typescript", "message": "console.{{METHOD}} in test block — use proper assertions or logging", "query": " (call_expression\n function: (member_expression\n object: (identifier) @OBJ (#eq? @OBJ \"console\")\n property: (property_identifier) @METHOD)\n arguments: (arguments) @ARGS)", "metavars": [ "OBJ", "METHOD", "ARGS" ], "post_filter": "in_test_block", "defect_class": "safety", "inline_tier": "warning" }, { "id": "no-dupe-class-members", "name": "Duplicate class member", "severity": "error", "language": "typescript", "message": "Duplicate class member '$NAME' - previous declaration will be overwritten", "query": " (class_body\n (method_definition\n name: (property_identifier) @NAME1\n (#match? @NAME1 \"^[^#]\"))\n (method_definition\n name: (property_identifier) @NAME2\n (#eq? @NAME1 @NAME2)))", "metavars": [ "NAME1", "NAME2" ], "defect_class": "correctness", "inline_tier": "blocking" }, { "id": "sql-injection", "name": "SQL Injection Risk", "severity": "error", "language": "typescript", "message": "SQL injection risk — use parameterized queries, never interpolate into SQL", "query": " (call_expression\n function: [\n (identifier) @SQL_FUNC\n (member_expression property: (property_identifier) @SQL_FUNC)\n ]\n arguments: (arguments\n (template_string (template_substitution) @INTERPOLATION))\n (#match? @SQL_FUNC \"^(query|execute|exec|run)$\"))", "metavars": [ "SQL_FUNC", "INTERPOLATION" ], "defect_class": "injection", "inline_tier": "blocking" }, { "id": "ts-command-injection", "name": "Command Injection Sink", "severity": "warning", "language": "typescript", "message": "Potential command injection sink — avoid child_process command execution with untrusted input", "query": " [\n (call_expression\n function: (member_expression\n object: (identifier) @MOD\n property: (property_identifier) @FN)\n arguments: (arguments) @ARGS)\n (call_expression\n function: (member_expression\n object: (member_expression\n object: (identifier) @MOD\n property: (property_identifier) @NS)\n property: (property_identifier) @FN)\n arguments: (arguments) @ARGS)\n ]\n (#eq? @MOD \"child_process\")\n (#match? @FN \"^(exec|execSync)$\")", "metavars": [ "MOD", "NS", "FN", "ARGS" ], "post_filter": "ts_command_injection_sink", "defect_class": "injection", "inline_tier": "warning" }, { "id": "ts-detached-async-call", "name": "Detached Async Call", "severity": "warning", "language": "typescript", "message": "Detached async call — ensure this Promise is awaited or explicitly handled", "query": " (expression_statement\n (call_expression\n function: [\n (identifier) @FN\n (member_expression\n property: (property_identifier) @FN)\n ]\n arguments: (arguments) @ARGS))\n (#match? @FN \"(Async$|fetch$|request$)\")", "metavars": [ "FN", "ARGS" ], "post_filter": "ts_detached_async_call", "defect_class": "async-misuse", "inline_tier": "warning" }, { "id": "ts-insecure-random", "name": "Insecure Randomness", "severity": "warning", "language": "typescript", "message": "Insecure randomness source detected — use crypto.getRandomValues or secure RNG APIs", "query": " (call_expression\n function: (member_expression\n object: (identifier) @OBJ\n property: (property_identifier) @FN)\n arguments: (arguments) @ARGS)\n (#eq? @OBJ \"Math\")\n (#eq? @FN \"random\")", "metavars": [ "OBJ", "FN", "ARGS" ], "post_filter": "ts_insecure_random_source", "defect_class": "injection", "inline_tier": "warning" }, { "id": "ts-ssrf", "name": "SSRF Risk", "severity": "warning", "language": "typescript", "message": "Potential SSRF sink — validate and allowlist outbound URLs", "query": " [\n (call_expression\n function: (identifier) @FN\n arguments: (arguments [(identifier) (member_expression) (call_expression)] @URL))\n (call_expression\n function: (member_expression\n object: (identifier) @OBJ\n property: (property_identifier) @FN)\n arguments: (arguments [(identifier) (member_expression) (call_expression)] @URL))\n ]\n (#match? @FN \"^(fetch|get|post|put|patch|delete|request)$\")", "metavars": [ "OBJ", "FN", "URL" ], "post_filter": "ts_ssrf_sink", "defect_class": "injection", "inline_tier": "warning" }, { "id": "ts-weak-hash", "name": "Weak Hash Primitive", "severity": "warning", "language": "typescript", "message": "Weak hash primitive selected (md5/sha1) — use sha256+ for security-sensitive contexts", "query": " (call_expression\n function: (member_expression\n property: (property_identifier) @FN)\n arguments: (arguments\n (string (string_fragment) @ALG)\n (_)*))\n (#eq? @FN \"createHash\")\n (#match? @ALG \"^(md5|sha1)$\")", "metavars": [ "FN", "ALG" ], "post_filter": "ts_weak_hash_algorithm", "defect_class": "injection", "inline_tier": "warning" }, { "id": "unsafe-regex", "name": "Dynamic Regex Construction", "severity": "error", "language": "typescript", "message": "Dynamic regex from user input — can cause ReDoS (Regular Expression Denial of Service)", "query": " (new_expression\n constructor: (identifier) @CTOR\n (#eq? @CTOR \"RegExp\")\n arguments: (arguments\n (template_string\n (template_substitution) @INTERPOLATION) @PATTERN))", "metavars": [ "CTOR", "INTERPOLATION", "PATTERN" ], "defect_class": "injection", "inline_tier": "blocking" }, { "id": "variable-shadowing", "name": "Variable Shadowing", "severity": "warning", "language": "typescript", "message": "Variable '{{NAME}}' shadows a parameter — use a distinct name", "query": " (function_declaration\n parameters: (formal_parameters\n (required_parameter\n pattern: (identifier) @PARAM))\n body: (statement_block\n (lexical_declaration\n (variable_declarator\n name: (identifier) @NAME))))", "metavars": [ "PARAM", "NAME" ], "post_filter": "name_matches_param", "defect_class": "safety", "inline_tier": "review" } ] }