@trust-assurance-protocol/owaspscan 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/dist/analysis/ast-analyzer.d.ts +13 -0
  2. package/dist/analysis/ast-analyzer.d.ts.map +1 -0
  3. package/dist/analysis/ast-analyzer.js +58 -0
  4. package/dist/analysis/ast-analyzer.js.map +1 -0
  5. package/dist/analysis/llm-verifier.d.ts +17 -0
  6. package/dist/analysis/llm-verifier.d.ts.map +1 -0
  7. package/dist/analysis/llm-verifier.js +152 -0
  8. package/dist/analysis/llm-verifier.js.map +1 -0
  9. package/dist/analysis/result-cache.d.ts +20 -0
  10. package/dist/analysis/result-cache.d.ts.map +1 -0
  11. package/dist/analysis/result-cache.js +70 -0
  12. package/dist/analysis/result-cache.js.map +1 -0
  13. package/dist/analysis/sinks.d.ts +12 -0
  14. package/dist/analysis/sinks.d.ts.map +1 -0
  15. package/dist/analysis/sinks.js +142 -0
  16. package/dist/analysis/sinks.js.map +1 -0
  17. package/dist/analysis/sources.d.ts +8 -0
  18. package/dist/analysis/sources.d.ts.map +1 -0
  19. package/dist/analysis/sources.js +114 -0
  20. package/dist/analysis/sources.js.map +1 -0
  21. package/dist/analysis/taint-engine.d.ts +5 -0
  22. package/dist/analysis/taint-engine.d.ts.map +1 -0
  23. package/dist/analysis/taint-engine.js +187 -0
  24. package/dist/analysis/taint-engine.js.map +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +227 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/config/loader.d.ts +10 -0
  30. package/dist/config/loader.d.ts.map +1 -0
  31. package/dist/config/loader.js +81 -0
  32. package/dist/config/loader.js.map +1 -0
  33. package/dist/config/schema.d.ts +23 -0
  34. package/dist/config/schema.d.ts.map +1 -0
  35. package/dist/config/schema.js +17 -0
  36. package/dist/config/schema.js.map +1 -0
  37. package/dist/mcp/server.d.ts +2 -0
  38. package/dist/mcp/server.d.ts.map +1 -0
  39. package/dist/mcp/server.js +250 -0
  40. package/dist/mcp/server.js.map +1 -0
  41. package/dist/parsers/ast-parser.d.ts +38 -0
  42. package/dist/parsers/ast-parser.d.ts.map +1 -0
  43. package/dist/parsers/ast-parser.js +88 -0
  44. package/dist/parsers/ast-parser.js.map +1 -0
  45. package/dist/parsers/ast-queries.d.ts +63 -0
  46. package/dist/parsers/ast-queries.d.ts.map +1 -0
  47. package/dist/parsers/ast-queries.js +580 -0
  48. package/dist/parsers/ast-queries.js.map +1 -0
  49. package/dist/reporter/console.d.ts +8 -0
  50. package/dist/reporter/console.d.ts.map +1 -0
  51. package/dist/reporter/console.js +143 -0
  52. package/dist/reporter/console.js.map +1 -0
  53. package/dist/reporter/json.d.ts +3 -0
  54. package/dist/reporter/json.d.ts.map +1 -0
  55. package/dist/reporter/json.js +7 -0
  56. package/dist/reporter/json.js.map +1 -0
  57. package/dist/reporter/llm.d.ts +3 -0
  58. package/dist/reporter/llm.d.ts.map +1 -0
  59. package/dist/reporter/llm.js +66 -0
  60. package/dist/reporter/llm.js.map +1 -0
  61. package/dist/reporter/sarif.d.ts +3 -0
  62. package/dist/reporter/sarif.d.ts.map +1 -0
  63. package/dist/reporter/sarif.js +110 -0
  64. package/dist/reporter/sarif.js.map +1 -0
  65. package/dist/rules/owasp-a01/idor.d.ts +3 -0
  66. package/dist/rules/owasp-a01/idor.d.ts.map +1 -0
  67. package/dist/rules/owasp-a01/idor.js +48 -0
  68. package/dist/rules/owasp-a01/idor.js.map +1 -0
  69. package/dist/rules/owasp-a01/missing-auth-middleware.d.ts +3 -0
  70. package/dist/rules/owasp-a01/missing-auth-middleware.d.ts.map +1 -0
  71. package/dist/rules/owasp-a01/missing-auth-middleware.js +41 -0
  72. package/dist/rules/owasp-a01/missing-auth-middleware.js.map +1 -0
  73. package/dist/rules/owasp-a01/path-traversal.d.ts +3 -0
  74. package/dist/rules/owasp-a01/path-traversal.d.ts.map +1 -0
  75. package/dist/rules/owasp-a01/path-traversal.js +73 -0
  76. package/dist/rules/owasp-a01/path-traversal.js.map +1 -0
  77. package/dist/rules/owasp-a02/hardcoded-secrets.d.ts +3 -0
  78. package/dist/rules/owasp-a02/hardcoded-secrets.d.ts.map +1 -0
  79. package/dist/rules/owasp-a02/hardcoded-secrets.js +97 -0
  80. package/dist/rules/owasp-a02/hardcoded-secrets.js.map +1 -0
  81. package/dist/rules/owasp-a02/insecure-tls.d.ts +3 -0
  82. package/dist/rules/owasp-a02/insecure-tls.d.ts.map +1 -0
  83. package/dist/rules/owasp-a02/insecure-tls.js +75 -0
  84. package/dist/rules/owasp-a02/insecure-tls.js.map +1 -0
  85. package/dist/rules/owasp-a02/weak-hash.d.ts +3 -0
  86. package/dist/rules/owasp-a02/weak-hash.d.ts.map +1 -0
  87. package/dist/rules/owasp-a02/weak-hash.js +73 -0
  88. package/dist/rules/owasp-a02/weak-hash.js.map +1 -0
  89. package/dist/rules/owasp-a02/weak-random.d.ts +3 -0
  90. package/dist/rules/owasp-a02/weak-random.d.ts.map +1 -0
  91. package/dist/rules/owasp-a02/weak-random.js +70 -0
  92. package/dist/rules/owasp-a02/weak-random.js.map +1 -0
  93. package/dist/rules/owasp-a03/command-injection.d.ts +3 -0
  94. package/dist/rules/owasp-a03/command-injection.d.ts.map +1 -0
  95. package/dist/rules/owasp-a03/command-injection.js +79 -0
  96. package/dist/rules/owasp-a03/command-injection.js.map +1 -0
  97. package/dist/rules/owasp-a03/ldap-injection.d.ts +3 -0
  98. package/dist/rules/owasp-a03/ldap-injection.d.ts.map +1 -0
  99. package/dist/rules/owasp-a03/ldap-injection.js +56 -0
  100. package/dist/rules/owasp-a03/ldap-injection.js.map +1 -0
  101. package/dist/rules/owasp-a03/nosql-injection.d.ts +3 -0
  102. package/dist/rules/owasp-a03/nosql-injection.d.ts.map +1 -0
  103. package/dist/rules/owasp-a03/nosql-injection.js +61 -0
  104. package/dist/rules/owasp-a03/nosql-injection.js.map +1 -0
  105. package/dist/rules/owasp-a03/sql-injection.d.ts +3 -0
  106. package/dist/rules/owasp-a03/sql-injection.d.ts.map +1 -0
  107. package/dist/rules/owasp-a03/sql-injection.js +88 -0
  108. package/dist/rules/owasp-a03/sql-injection.js.map +1 -0
  109. package/dist/rules/owasp-a03/template-injection.d.ts +3 -0
  110. package/dist/rules/owasp-a03/template-injection.d.ts.map +1 -0
  111. package/dist/rules/owasp-a03/template-injection.js +64 -0
  112. package/dist/rules/owasp-a03/template-injection.js.map +1 -0
  113. package/dist/rules/owasp-a03/xss.d.ts +3 -0
  114. package/dist/rules/owasp-a03/xss.d.ts.map +1 -0
  115. package/dist/rules/owasp-a03/xss.js +74 -0
  116. package/dist/rules/owasp-a03/xss.js.map +1 -0
  117. package/dist/rules/owasp-a04/mass-assignment.d.ts +3 -0
  118. package/dist/rules/owasp-a04/mass-assignment.d.ts.map +1 -0
  119. package/dist/rules/owasp-a04/mass-assignment.js +63 -0
  120. package/dist/rules/owasp-a04/mass-assignment.js.map +1 -0
  121. package/dist/rules/owasp-a04/missing-rate-limit.d.ts +3 -0
  122. package/dist/rules/owasp-a04/missing-rate-limit.d.ts.map +1 -0
  123. package/dist/rules/owasp-a04/missing-rate-limit.js +48 -0
  124. package/dist/rules/owasp-a04/missing-rate-limit.js.map +1 -0
  125. package/dist/rules/owasp-a05/cors-wildcard.d.ts +3 -0
  126. package/dist/rules/owasp-a05/cors-wildcard.d.ts.map +1 -0
  127. package/dist/rules/owasp-a05/cors-wildcard.js +79 -0
  128. package/dist/rules/owasp-a05/cors-wildcard.js.map +1 -0
  129. package/dist/rules/owasp-a05/debug-mode.d.ts +3 -0
  130. package/dist/rules/owasp-a05/debug-mode.d.ts.map +1 -0
  131. package/dist/rules/owasp-a05/debug-mode.js +73 -0
  132. package/dist/rules/owasp-a05/debug-mode.js.map +1 -0
  133. package/dist/rules/owasp-a05/default-credentials.d.ts +3 -0
  134. package/dist/rules/owasp-a05/default-credentials.d.ts.map +1 -0
  135. package/dist/rules/owasp-a05/default-credentials.js +52 -0
  136. package/dist/rules/owasp-a05/default-credentials.js.map +1 -0
  137. package/dist/rules/owasp-a05/error-disclosure.d.ts +3 -0
  138. package/dist/rules/owasp-a05/error-disclosure.d.ts.map +1 -0
  139. package/dist/rules/owasp-a05/error-disclosure.js +70 -0
  140. package/dist/rules/owasp-a05/error-disclosure.js.map +1 -0
  141. package/dist/rules/owasp-a06/outdated-packages.d.ts +3 -0
  142. package/dist/rules/owasp-a06/outdated-packages.d.ts.map +1 -0
  143. package/dist/rules/owasp-a06/outdated-packages.js +75 -0
  144. package/dist/rules/owasp-a06/outdated-packages.js.map +1 -0
  145. package/dist/rules/owasp-a07/insecure-cookies.d.ts +3 -0
  146. package/dist/rules/owasp-a07/insecure-cookies.d.ts.map +1 -0
  147. package/dist/rules/owasp-a07/insecure-cookies.js +64 -0
  148. package/dist/rules/owasp-a07/insecure-cookies.js.map +1 -0
  149. package/dist/rules/owasp-a07/jwt-none-alg.d.ts +3 -0
  150. package/dist/rules/owasp-a07/jwt-none-alg.d.ts.map +1 -0
  151. package/dist/rules/owasp-a07/jwt-none-alg.js +81 -0
  152. package/dist/rules/owasp-a07/jwt-none-alg.js.map +1 -0
  153. package/dist/rules/owasp-a07/no-password-hashing.d.ts +3 -0
  154. package/dist/rules/owasp-a07/no-password-hashing.d.ts.map +1 -0
  155. package/dist/rules/owasp-a07/no-password-hashing.js +70 -0
  156. package/dist/rules/owasp-a07/no-password-hashing.js.map +1 -0
  157. package/dist/rules/owasp-a07/weak-session.d.ts +3 -0
  158. package/dist/rules/owasp-a07/weak-session.d.ts.map +1 -0
  159. package/dist/rules/owasp-a07/weak-session.js +64 -0
  160. package/dist/rules/owasp-a07/weak-session.js.map +1 -0
  161. package/dist/rules/owasp-a08/unsafe-deserialization.d.ts +3 -0
  162. package/dist/rules/owasp-a08/unsafe-deserialization.d.ts.map +1 -0
  163. package/dist/rules/owasp-a08/unsafe-deserialization.js +78 -0
  164. package/dist/rules/owasp-a08/unsafe-deserialization.js.map +1 -0
  165. package/dist/rules/owasp-a08/unsafe-eval.d.ts +3 -0
  166. package/dist/rules/owasp-a08/unsafe-eval.d.ts.map +1 -0
  167. package/dist/rules/owasp-a08/unsafe-eval.js +73 -0
  168. package/dist/rules/owasp-a08/unsafe-eval.js.map +1 -0
  169. package/dist/rules/owasp-a09/log-sensitive-data.d.ts +3 -0
  170. package/dist/rules/owasp-a09/log-sensitive-data.d.ts.map +1 -0
  171. package/dist/rules/owasp-a09/log-sensitive-data.js +73 -0
  172. package/dist/rules/owasp-a09/log-sensitive-data.js.map +1 -0
  173. package/dist/rules/owasp-a09/missing-error-handling.d.ts +3 -0
  174. package/dist/rules/owasp-a09/missing-error-handling.d.ts.map +1 -0
  175. package/dist/rules/owasp-a09/missing-error-handling.js +84 -0
  176. package/dist/rules/owasp-a09/missing-error-handling.js.map +1 -0
  177. package/dist/rules/owasp-a10/open-redirect.d.ts +3 -0
  178. package/dist/rules/owasp-a10/open-redirect.d.ts.map +1 -0
  179. package/dist/rules/owasp-a10/open-redirect.js +67 -0
  180. package/dist/rules/owasp-a10/open-redirect.js.map +1 -0
  181. package/dist/rules/owasp-a10/unvalidated-fetch.d.ts +3 -0
  182. package/dist/rules/owasp-a10/unvalidated-fetch.d.ts.map +1 -0
  183. package/dist/rules/owasp-a10/unvalidated-fetch.js +85 -0
  184. package/dist/rules/owasp-a10/unvalidated-fetch.js.map +1 -0
  185. package/dist/rules/registry.d.ts +20 -0
  186. package/dist/rules/registry.d.ts.map +1 -0
  187. package/dist/rules/registry.js +142 -0
  188. package/dist/rules/registry.js.map +1 -0
  189. package/dist/scanner/engine.d.ts +21 -0
  190. package/dist/scanner/engine.d.ts.map +1 -0
  191. package/dist/scanner/engine.js +260 -0
  192. package/dist/scanner/engine.js.map +1 -0
  193. package/dist/scanner/file-walker.d.ts +7 -0
  194. package/dist/scanner/file-walker.d.ts.map +1 -0
  195. package/dist/scanner/file-walker.js +81 -0
  196. package/dist/scanner/file-walker.js.map +1 -0
  197. package/dist/scanner/language-detect.d.ts +5 -0
  198. package/dist/scanner/language-detect.d.ts.map +1 -0
  199. package/dist/scanner/language-detect.js +91 -0
  200. package/dist/scanner/language-detect.js.map +1 -0
  201. package/dist/scanner/sca-scanner.d.ts +38 -0
  202. package/dist/scanner/sca-scanner.d.ts.map +1 -0
  203. package/dist/scanner/sca-scanner.js +223 -0
  204. package/dist/scanner/sca-scanner.js.map +1 -0
  205. package/dist/types/index.d.ts +114 -0
  206. package/dist/types/index.d.ts.map +1 -0
  207. package/dist/types/index.js +25 -0
  208. package/dist/types/index.js.map +1 -0
  209. package/dist/utils/pattern-matcher.d.ts +4 -0
  210. package/dist/utils/pattern-matcher.d.ts.map +1 -0
  211. package/dist/utils/pattern-matcher.js +72 -0
  212. package/dist/utils/pattern-matcher.js.map +1 -0
  213. package/dist/utils/scoring.d.ts +8 -0
  214. package/dist/utils/scoring.d.ts.map +1 -0
  215. package/dist/utils/scoring.js +76 -0
  216. package/dist/utils/scoring.js.map +1 -0
  217. package/dist/utils/suppression.d.ts +3 -0
  218. package/dist/utils/suppression.d.ts.map +1 -0
  219. package/dist/utils/suppression.js +33 -0
  220. package/dist/utils/suppression.js.map +1 -0
  221. package/package.json +94 -0
@@ -0,0 +1,88 @@
1
+ // OWASP A03:2021 — Injection
2
+ // Rule: SQL Injection via string concatenation or template literals
3
+ export const SqlInjection = {
4
+ id: 'OWASP-A03-001',
5
+ name: 'SQL Injection via String Concatenation or Template Literal',
6
+ owasp: 'A03:2021',
7
+ cwe: 'CWE-89',
8
+ severity: 'CRITICAL',
9
+ languages: ['javascript', 'typescript', 'python', 'php', 'java', 'ruby', 'go', 'csharp'],
10
+ description: 'SQL query built by concatenating or interpolating user-controlled input. ' +
11
+ 'Attackers can break out of the query string and execute arbitrary SQL commands, ' +
12
+ 'reading, modifying, or deleting any data in the database. ' +
13
+ 'The #1 most common AI-generated security bug — AI assistants use string concat for convenience.',
14
+ patterns: [
15
+ {
16
+ // SQL keyword in a string concatenated with user input — broad pattern
17
+ pattern: /(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|WHERE|UNION)\b[^\n]{0,200}\+[^\n]{0,100}(?:req\.|request\.)(?:params|body|query)\b/gi,
18
+ snippetLines: 3,
19
+ },
20
+ {
21
+ // db/client.query with concat directly
22
+ pattern: /(?:db|pool|client|conn|connection)\s*\.\s*(?:query|execute|run|exec)\s*\([^\n]*\+[^\n]*(?:req\.|request\.)(?:params|body|query)\b/gi,
23
+ snippetLines: 3,
24
+ },
25
+ {
26
+ // Template literal SQL with user input (JS/TS)
27
+ pattern: /`\s*(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|WHERE|UNION)\b[^`]*\$\{[^}]*(?:req\.|request\.|params\.|query\.|body\.|user\.|input\.|data\.)/gi,
28
+ snippetLines: 3,
29
+ },
30
+ {
31
+ // db.query/execute/run with string concat (JS/TS)
32
+ pattern: /(?:db|conn|pool|client|connection|knex)\s*\.\s*(?:query|execute|run|exec|raw)\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi,
33
+ snippetLines: 3,
34
+ },
35
+ {
36
+ // Python: cursor.execute with format string or % operator
37
+ pattern: /cursor\s*\.\s*execute\s*\(\s*['"`][^'"`]*(?:SELECT|INSERT|UPDATE|DELETE|WHERE)[^'"`]*['"`]\s*%\s*(?:request\.|req\.)/gi,
38
+ snippetLines: 3,
39
+ },
40
+ {
41
+ // Python: f-string SQL
42
+ pattern: /cursor\s*\.\s*execute\s*\(\s*f['"`][^'"`]*(?:SELECT|INSERT|UPDATE|DELETE|WHERE)[^'"`]*\{[^}]*(?:request\.|req\.)/gi,
43
+ snippetLines: 3,
44
+ },
45
+ {
46
+ // PHP: mysql_query / mysqli_query with string concat
47
+ pattern: /(?:mysql_query|mysqli_query|pg_query)\s*\(\s*[^,]*['"`][^'"`]*(?:SELECT|INSERT|UPDATE|DELETE)[^'"`]*['"`]\s*\./gi,
48
+ snippetLines: 3,
49
+ },
50
+ {
51
+ // Java: Statement.executeQuery with string concat
52
+ pattern: /(?:stmt|statement|conn)\s*\.\s*execute(?:Query|Update)?\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi,
53
+ snippetLines: 3,
54
+ },
55
+ {
56
+ // Go: db.Query with Sprintf
57
+ pattern: /(?:db|tx)\s*\.\s*(?:Query|Exec|QueryRow)\s*\(\s*fmt\.Sprintf\s*\(\s*['"`][^'"`]*(?:SELECT|INSERT|UPDATE|DELETE|WHERE)/gi,
58
+ snippetLines: 3,
59
+ },
60
+ ],
61
+ fix: 'ALWAYS use parameterized queries (prepared statements) — never concatenate user input into SQL.\n\n' +
62
+ '// Node.js + mysql2:\n' +
63
+ 'const [rows] = await db.query(\n' +
64
+ ' "SELECT * FROM users WHERE id = ? AND email = ?",\n' +
65
+ ' [req.params.id, req.body.email] // parameters passed separately\n' +
66
+ ');\n\n' +
67
+ '// Node.js + pg:\n' +
68
+ 'const result = await client.query(\n' +
69
+ ' "SELECT * FROM users WHERE id = $1",\n' +
70
+ ' [req.params.id]\n' +
71
+ ');\n\n' +
72
+ '// Python:\n' +
73
+ 'cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))\n\n' +
74
+ '// PHP + PDO:\n' +
75
+ '$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");\n' +
76
+ '$stmt->execute([$_GET["id"]]);\n\n' +
77
+ '// Java:\n' +
78
+ 'PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?");\n' +
79
+ 'ps.setInt(1, userId);',
80
+ references: [
81
+ 'https://owasp.org/Top10/A03_2021-Injection/',
82
+ 'https://cwe.mitre.org/data/definitions/89.html',
83
+ 'https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html',
84
+ 'https://portswigger.net/web-security/sql-injection',
85
+ ],
86
+ tags: ['injection', 'sql', 'database', 'sqli'],
87
+ };
88
+ //# sourceMappingURL=sql-injection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-injection.js","sourceRoot":"","sources":["../../../src/rules/owasp-a03/sql-injection.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,oEAAoE;AAIpE,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,4DAA4D;IAClE,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,QAAQ;IACb,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC;IACxF,WAAW,EACT,2EAA2E;QAC3E,kFAAkF;QAClF,4DAA4D;QAC5D,iGAAiG;IACnG,QAAQ,EAAE;QACR;YACE,uEAAuE;YACvE,OAAO,EACL,gIAAgI;YAClI,YAAY,EAAE,CAAC;SAChB;QACD;YACE,uCAAuC;YACvC,OAAO,EACL,qIAAqI;YACvI,YAAY,EAAE,CAAC;SAChB;QACD;YACE,+CAA+C;YAC/C,OAAO,EACL,+IAA+I;YACjJ,YAAY,EAAE,CAAC;SAChB;QACD;YACE,kDAAkD;YAClD,OAAO,EACL,+GAA+G;YACjH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,0DAA0D;YAC1D,OAAO,EACL,wHAAwH;YAC1H,YAAY,EAAE,CAAC;SAChB;QACD;YACE,uBAAuB;YACvB,OAAO,EACL,oHAAoH;YACtH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,qDAAqD;YACrD,OAAO,EACL,kHAAkH;YACpH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,kDAAkD;YAClD,OAAO,EACL,yFAAyF;YAC3F,YAAY,EAAE,CAAC;SAChB;QACD;YACE,4BAA4B;YAC5B,OAAO,EACL,yHAAyH;YAC3H,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,qGAAqG;QACrG,wBAAwB;QACxB,kCAAkC;QAClC,uDAAuD;QACvD,qEAAqE;QACrE,QAAQ;QACR,oBAAoB;QACpB,sCAAsC;QACtC,0CAA0C;QAC1C,qBAAqB;QACrB,QAAQ;QACR,cAAc;QACd,qEAAqE;QACrE,iBAAiB;QACjB,8DAA8D;QAC9D,oCAAoC;QACpC,YAAY;QACZ,qFAAqF;QACrF,uBAAuB;IACzB,UAAU,EAAE;QACV,6CAA6C;QAC7C,gDAAgD;QAChD,0FAA0F;QAC1F,oDAAoD;KACrD;IACD,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC;CAC/C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const TemplateInjection: Rule;
3
+ //# sourceMappingURL=template-injection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-injection.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a03/template-injection.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,iBAAiB,EAAE,IAoE/B,CAAC"}
@@ -0,0 +1,64 @@
1
+ // OWASP A03:2021 — Injection
2
+ // Rule: Server-Side Template Injection (SSTI)
3
+ export const TemplateInjection = {
4
+ id: 'OWASP-A03-005',
5
+ name: 'Server-Side Template Injection (SSTI)',
6
+ owasp: 'A03:2021',
7
+ cwe: 'CWE-94',
8
+ severity: 'CRITICAL',
9
+ languages: ['javascript', 'typescript', 'python', 'php', 'ruby', 'java'],
10
+ description: 'User input passed to a template engine as a template string (not as data) allows ' +
11
+ 'attackers to execute arbitrary code on the server. A classic example: passing ' +
12
+ 'req.body.template to pug.render() or env.from_string() with user content.',
13
+ patterns: [
14
+ {
15
+ // Pug/Jade: render/compile with user input as template
16
+ pattern: /(?:pug|jade)\s*\.\s*(?:render|compile|renderFile)\s*\([^)]*(?:req\.|request\.)(?:body|params|query)/gi,
17
+ snippetLines: 3,
18
+ },
19
+ {
20
+ // Handlebars: compile/precompile with user template
21
+ pattern: /(?:Handlebars|hbs)\s*\.\s*(?:compile|precompile)\s*\([^)]*(?:req\.|request\.)(?:body|params|query)/gi,
22
+ snippetLines: 3,
23
+ },
24
+ {
25
+ // EJS: render with user input as template string
26
+ pattern: /ejs\s*\.\s*render\s*\([^)]*(?:req\.|request\.)(?:body|params|query)/gi,
27
+ snippetLines: 3,
28
+ },
29
+ {
30
+ // Python Jinja2: from_string with user input
31
+ pattern: /(?:env|environment|jinja2)\s*\.\s*from_string\s*\([^)]*(?:request\.|req\.)(?:args|form|json|data)/gi,
32
+ snippetLines: 3,
33
+ },
34
+ {
35
+ // Python Jinja2: Template() with user content
36
+ pattern: /jinja2\s*\.\s*Template\s*\([^)]*(?:request\.|req\.)(?:args|form|json|data)/gi,
37
+ snippetLines: 3,
38
+ },
39
+ {
40
+ // Mako/Genshi template from user input
41
+ pattern: /Template\s*\(\s*text\s*=\s*(?:request\.|req\.)(?:args|form|json|data)/gi,
42
+ snippetLines: 3,
43
+ },
44
+ ],
45
+ fix: 'Never use user input AS a template. Only pass user data INTO templates as context variables.\n\n' +
46
+ '// BAD:\n' +
47
+ 'const html = pug.render(req.body.template, { user }); // SSTI!\n\n' +
48
+ '// GOOD — load template from filesystem, pass user data as context:\n' +
49
+ 'const html = pug.renderFile("views/profile.pug", {\n' +
50
+ ' username: req.body.username, // data, not template code\n' +
51
+ '});\n\n' +
52
+ '// Python Jinja2 — BAD:\n' +
53
+ 'template = jinja2.Template(request.args["tmpl"]) # SSTI!\n\n' +
54
+ '// GOOD:\n' +
55
+ 'template = env.get_template("profile.html") # from filesystem\n' +
56
+ 'html = template.render(username=request.args.get("username", ""))',
57
+ references: [
58
+ 'https://owasp.org/Top10/A03_2021-Injection/',
59
+ 'https://cwe.mitre.org/data/definitions/94.html',
60
+ 'https://portswigger.net/web-security/server-side-template-injection',
61
+ ],
62
+ tags: ['injection', 'ssti', 'template', 'rce'],
63
+ };
64
+ //# sourceMappingURL=template-injection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-injection.js","sourceRoot":"","sources":["../../../src/rules/owasp-a03/template-injection.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,8CAA8C;AAI9C,MAAM,CAAC,MAAM,iBAAiB,GAAS;IACrC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,uCAAuC;IAC7C,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,QAAQ;IACb,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;IACxE,WAAW,EACT,mFAAmF;QACnF,gFAAgF;QAChF,2EAA2E;IAC7E,QAAQ,EAAE;QACR;YACE,uDAAuD;YACvD,OAAO,EACL,uGAAuG;YACzG,YAAY,EAAE,CAAC;SAChB;QACD;YACE,oDAAoD;YACpD,OAAO,EACL,sGAAsG;YACxG,YAAY,EAAE,CAAC;SAChB;QACD;YACE,iDAAiD;YACjD,OAAO,EACL,uEAAuE;YACzE,YAAY,EAAE,CAAC;SAChB;QACD;YACE,6CAA6C;YAC7C,OAAO,EACL,qGAAqG;YACvG,YAAY,EAAE,CAAC;SAChB;QACD;YACE,8CAA8C;YAC9C,OAAO,EACL,8EAA8E;YAChF,YAAY,EAAE,CAAC;SAChB;QACD;YACE,uCAAuC;YACvC,OAAO,EACL,yEAAyE;YAC3E,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,kGAAkG;QAClG,WAAW;QACX,oEAAoE;QACpE,uEAAuE;QACvE,sDAAsD;QACtD,6DAA6D;QAC7D,SAAS;QACT,2BAA2B;QAC3B,+DAA+D;QAC/D,YAAY;QACZ,kEAAkE;QAClE,mEAAmE;IACrE,UAAU,EAAE;QACV,6CAA6C;QAC7C,gDAAgD;QAChD,qEAAqE;KACtE;IACD,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC;CAC/C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const XssReflected: Rule;
3
+ //# sourceMappingURL=xss.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xss.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a03/xss.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,YAAY,EAAE,IA6E1B,CAAC"}
@@ -0,0 +1,74 @@
1
+ // OWASP A03:2021 — Injection
2
+ // Rule: Reflected / Stored XSS via unsanitized user input in HTML response
3
+ export const XssReflected = {
4
+ id: 'OWASP-A03-004',
5
+ name: 'Cross-Site Scripting (XSS) via Unsanitized User Input',
6
+ owasp: 'A03:2021',
7
+ cwe: 'CWE-79',
8
+ severity: 'HIGH',
9
+ languages: ['javascript', 'typescript', 'python', 'php', 'ruby', 'java'],
10
+ description: 'User-controlled input rendered directly into HTML without escaping. Attackers inject ' +
11
+ 'JavaScript that executes in victims\' browsers — stealing cookies, tokens, or performing ' +
12
+ 'actions on the user\'s behalf. AI tools often use innerHTML, dangerouslySetInnerHTML, ' +
13
+ 'or res.send() with unescaped user data.',
14
+ patterns: [
15
+ {
16
+ // JS: element.innerHTML with user input
17
+ pattern: /(?:\w+)\s*\.\s*innerHTML\s*=\s*(?!['"`][^'"`]*['"`])[^;]*(?:req\.|request\.|params\.|query\.|body\.|input\.|data\.)/gi,
18
+ snippetLines: 3,
19
+ },
20
+ {
21
+ // JS: document.write with user input
22
+ pattern: /document\s*\.\s*write\s*\([^)]*(?:req\.|request\.|location\.|search\.|hash\.|params\.)/gi,
23
+ snippetLines: 3,
24
+ },
25
+ {
26
+ // React: dangerouslySetInnerHTML with user content
27
+ pattern: /dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:\s*(?!DOMPurify|sanitize)[^}]*(?:req\.|props\.|state\.|user\.|data\.)/gi,
28
+ suppressIf: /DOMPurify|sanitizeHtml|xss-filters|sanitize/i,
29
+ snippetLines: 3,
30
+ },
31
+ {
32
+ // Express: res.send() / res.write() with user input (reflected)
33
+ pattern: /res\s*\.\s*(?:send|write)\s*\([^)]*(?:req\.|request\.)(?:body|params|query|headers)/gi,
34
+ snippetLines: 3,
35
+ },
36
+ {
37
+ // PHP: echo/print with $_GET/$_POST without htmlspecialchars
38
+ pattern: /(?:echo|print)\s+(?!\s*htmlspecialchars|\s*htmlentities|\s*strip_tags)\s*\$_(?:GET|POST|REQUEST|COOKIE)\s*\[/gi,
39
+ snippetLines: 3,
40
+ },
41
+ {
42
+ // Python/Flask: Markup() — bypasses Jinja2 auto-escaping
43
+ pattern: /Markup\s*\(\s*(?!.*escape\(|.*markupsafe)/gi,
44
+ requiresContext: /(?:request\.|form\.|args\.|json\.|data\.)/i,
45
+ snippetLines: 3,
46
+ },
47
+ {
48
+ // Template: |safe filter in Jinja2/Django with user data
49
+ pattern: /\{\{\s*[^}]*(?:request\.|form\.|args\.|data\.|user\.)[^|]*\|\s*safe\s*\}\}/gi,
50
+ snippetLines: 3,
51
+ },
52
+ ],
53
+ fix: 'Always escape user input before rendering in HTML context.\n\n' +
54
+ '// Node.js — use a sanitization library:\n' +
55
+ 'import DOMPurify from "dompurify";\n' +
56
+ 'import { JSDOM } from "jsdom";\n' +
57
+ 'const window = new JSDOM("").window;\n' +
58
+ 'const purify = DOMPurify(window);\n' +
59
+ 'element.innerHTML = purify.sanitize(userInput); // sanitized\n\n' +
60
+ '// Express — escape output:\n' +
61
+ 'import escapeHtml from "escape-html";\n' +
62
+ 'res.send(`<p>${escapeHtml(req.query.name)}</p>`);\n\n' +
63
+ '// PHP:\n' +
64
+ 'echo htmlspecialchars($_GET["name"], ENT_QUOTES, "UTF-8");\n\n' +
65
+ '// Prefer template engines with auto-escaping (Jinja2, EJS, Handlebars)\n' +
66
+ '// and avoid |safe, {{{ }}}, or Markup() with user data.',
67
+ references: [
68
+ 'https://owasp.org/Top10/A03_2021-Injection/',
69
+ 'https://cwe.mitre.org/data/definitions/79.html',
70
+ 'https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html',
71
+ ],
72
+ tags: ['injection', 'xss', 'cross-site-scripting', 'html', 'output-encoding'],
73
+ };
74
+ //# sourceMappingURL=xss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xss.js","sourceRoot":"","sources":["../../../src/rules/owasp-a03/xss.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,2EAA2E;AAI3E,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,uDAAuD;IAC7D,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,QAAQ;IACb,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;IACxE,WAAW,EACT,uFAAuF;QACvF,2FAA2F;QAC3F,wFAAwF;QACxF,yCAAyC;IAC3C,QAAQ,EAAE;QACR;YACE,wCAAwC;YACxC,OAAO,EACL,uHAAuH;YACzH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,qCAAqC;YACrC,OAAO,EACL,0FAA0F;YAC5F,YAAY,EAAE,CAAC;SAChB;QACD;YACE,mDAAmD;YACnD,OAAO,EACL,2HAA2H;YAC7H,UAAU,EAAE,8CAA8C;YAC1D,YAAY,EAAE,CAAC;SAChB;QACD;YACE,gEAAgE;YAChE,OAAO,EACL,uFAAuF;YACzF,YAAY,EAAE,CAAC;SAChB;QACD;YACE,6DAA6D;YAC7D,OAAO,EACL,gHAAgH;YAClH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,yDAAyD;YACzD,OAAO,EAAE,6CAA6C;YACtD,eAAe,EAAE,4CAA4C;YAC7D,YAAY,EAAE,CAAC;SAChB;QACD;YACE,yDAAyD;YACzD,OAAO,EAAE,8EAA8E;YACvF,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,gEAAgE;QAChE,4CAA4C;QAC5C,sCAAsC;QACtC,kCAAkC;QAClC,wCAAwC;QACxC,qCAAqC;QACrC,kEAAkE;QAClE,+BAA+B;QAC/B,yCAAyC;QACzC,uDAAuD;QACvD,WAAW;QACX,gEAAgE;QAChE,2EAA2E;QAC3E,0DAA0D;IAC5D,UAAU,EAAE;QACV,6CAA6C;QAC7C,gDAAgD;QAChD,iGAAiG;KAClG;IACD,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,iBAAiB,CAAC;CAC9E,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const MassAssignment: Rule;
3
+ //# sourceMappingURL=mass-assignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mass-assignment.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a04/mass-assignment.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,cAAc,EAAE,IAiE5B,CAAC"}
@@ -0,0 +1,63 @@
1
+ // OWASP A04:2021 — Insecure Design
2
+ // Rule: Mass Assignment vulnerability (binding all request fields to model)
3
+ export const MassAssignment = {
4
+ id: 'OWASP-A04-002',
5
+ name: 'Mass Assignment Vulnerability',
6
+ owasp: 'A04:2021',
7
+ cwe: 'CWE-915',
8
+ severity: 'HIGH',
9
+ languages: ['javascript', 'typescript', 'python', 'ruby', 'php'],
10
+ description: 'Binding all request body fields directly to a model object (e.g., User.create(req.body)) ' +
11
+ 'allows attackers to set fields they should not control — such as isAdmin, role, balance, ' +
12
+ 'or verified. AI tools commonly generate Model.create(req.body) for convenience.',
13
+ patterns: [
14
+ {
15
+ // Mongoose/Sequelize: Model.create(req.body) or new Model(req.body)
16
+ pattern: /(?:\w+)\s*\.\s*(?:create|build|insert|insertMany)\s*\(\s*req\s*\.\s*body\s*\)/gi,
17
+ snippetLines: 3,
18
+ },
19
+ {
20
+ // new Model(req.body) — passing entire body to constructor
21
+ pattern: /new\s+\w+\s*\(\s*req\s*\.\s*body\s*\)/g,
22
+ suppressIf: /(?:error|Error|exception|Exception|event|Event|stream|Stream)/i,
23
+ snippetLines: 3,
24
+ },
25
+ {
26
+ // Object spread: { ...req.body } into DB operations
27
+ pattern: /(?:create|update|save|insert|upsert)\s*\(\s*\{\s*\.\.\.\s*req\s*\.\s*body/gi,
28
+ snippetLines: 3,
29
+ },
30
+ {
31
+ // Object.assign(model, req.body)
32
+ pattern: /Object\s*\.\s*assign\s*\([^,]+,\s*req\s*\.\s*body\s*\)/gi,
33
+ snippetLines: 3,
34
+ },
35
+ {
36
+ // Python Django: Model(**request.data) or form.save() without field restriction
37
+ pattern: /\w+\s*\(\s*\*\*\s*request\.(?:data|POST|json)\s*\)/gi,
38
+ snippetLines: 3,
39
+ },
40
+ ],
41
+ fix: 'Explicitly whitelist the fields you accept from user input. Never pass req.body directly to a model.\n\n' +
42
+ '// BAD:\n' +
43
+ 'const user = await User.create(req.body); // attacker sets isAdmin: true\n\n' +
44
+ '// GOOD — explicit field extraction:\n' +
45
+ 'const { name, email, password } = req.body;\n' +
46
+ 'const user = await User.create({\n' +
47
+ ' name,\n' +
48
+ ' email,\n' +
49
+ ' password: await bcrypt.hash(password, 12),\n' +
50
+ ' // isAdmin NOT included — cannot be set by user\n' +
51
+ '});\n\n' +
52
+ '// Alternatively, use a validation library like Zod:\n' +
53
+ 'import { z } from "zod";\n' +
54
+ 'const CreateUserSchema = z.object({ name: z.string(), email: z.string().email() });\n' +
55
+ 'const data = CreateUserSchema.parse(req.body); // strips unknown fields',
56
+ references: [
57
+ 'https://owasp.org/Top10/A04_2021-Insecure_Design/',
58
+ 'https://cwe.mitre.org/data/definitions/915.html',
59
+ 'https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html',
60
+ ],
61
+ tags: ['mass-assignment', 'input-validation', 'design', 'authorization'],
62
+ };
63
+ //# sourceMappingURL=mass-assignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mass-assignment.js","sourceRoot":"","sources":["../../../src/rules/owasp-a04/mass-assignment.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,4EAA4E;AAI5E,MAAM,CAAC,MAAM,cAAc,GAAS;IAClC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,+BAA+B;IACrC,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;IAChE,WAAW,EACT,2FAA2F;QAC3F,2FAA2F;QAC3F,iFAAiF;IACnF,QAAQ,EAAE;QACR;YACE,oEAAoE;YACpE,OAAO,EACL,iFAAiF;YACnF,YAAY,EAAE,CAAC;SAChB;QACD;YACE,2DAA2D;YAC3D,OAAO,EACL,wCAAwC;YAC1C,UAAU,EAAE,gEAAgE;YAC5E,YAAY,EAAE,CAAC;SAChB;QACD;YACE,oDAAoD;YACpD,OAAO,EACL,6EAA6E;YAC/E,YAAY,EAAE,CAAC;SAChB;QACD;YACE,iCAAiC;YACjC,OAAO,EAAE,0DAA0D;YACnE,YAAY,EAAE,CAAC;SAChB;QACD;YACE,gFAAgF;YAChF,OAAO,EACL,sDAAsD;YACxD,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,0GAA0G;QAC1G,WAAW;QACX,8EAA8E;QAC9E,wCAAwC;QACxC,+CAA+C;QAC/C,oCAAoC;QACpC,WAAW;QACX,YAAY;QACZ,gDAAgD;QAChD,qDAAqD;QACrD,SAAS;QACT,wDAAwD;QACxD,4BAA4B;QAC5B,uFAAuF;QACvF,yEAAyE;IAC3E,UAAU,EAAE;QACV,mDAAmD;QACnD,iDAAiD;QACjD,iFAAiF;KAClF;IACD,IAAI,EAAE,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,eAAe,CAAC;CACzE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const MissingRateLimit: Rule;
3
+ //# sourceMappingURL=missing-rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-rate-limit.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a04/missing-rate-limit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,gBAAgB,EAAE,IAkD9B,CAAC"}
@@ -0,0 +1,48 @@
1
+ // OWASP A04:2021 — Insecure Design
2
+ // Rule: Missing rate limiting on sensitive endpoints
3
+ export const MissingRateLimit = {
4
+ id: 'OWASP-A04-001',
5
+ name: 'Missing Rate Limiting on Sensitive Endpoint',
6
+ owasp: 'A04:2021',
7
+ cwe: 'CWE-770',
8
+ severity: 'MEDIUM',
9
+ languages: ['javascript', 'typescript'],
10
+ description: 'Authentication, password reset, OTP verification, and account registration endpoints ' +
11
+ 'without rate limiting are vulnerable to brute-force attacks, credential stuffing, and ' +
12
+ 'account enumeration. AI tools rarely add rate limiting when generating auth routes.',
13
+ patterns: [
14
+ {
15
+ // Express login route without rate limiter
16
+ pattern: /(?:app|router)\s*\.\s*post\s*\(\s*['"`][^'"`]*(?:login|signin|sign-in|auth|authenticate|token|otp|verify|reset-password|forgot-password)[^'"`]*['"`]/gi,
17
+ suppressIf: /(?:rateLimit|rateLimiter|rate_limit|throttle|limiter|slowDown|express-rate-limit|@nestjs\/throttler|throttler)/i,
18
+ snippetLines: 3,
19
+ },
20
+ {
21
+ // Registration endpoint without rate limiting
22
+ pattern: /(?:app|router)\s*\.\s*post\s*\(\s*['"`][^'"`]*(?:register|signup|sign-up|create-account|new-user)[^'"`]*['"`]/gi,
23
+ suppressIf: /(?:rateLimit|rateLimiter|rate_limit|throttle|limiter|slowDown|express-rate-limit)/i,
24
+ snippetLines: 3,
25
+ },
26
+ ],
27
+ fix: 'Add rate limiting to all authentication and sensitive endpoints.\n\n' +
28
+ '// Express with express-rate-limit:\n' +
29
+ 'import rateLimit from "express-rate-limit";\n\n' +
30
+ 'const loginLimiter = rateLimit({\n' +
31
+ ' windowMs: 15 * 60 * 1000, // 15 minutes\n' +
32
+ ' max: 5, // max 5 login attempts per IP per window\n' +
33
+ ' message: { error: "Too many login attempts. Try again in 15 minutes." },\n' +
34
+ ' standardHeaders: true,\n' +
35
+ ' legacyHeaders: false,\n' +
36
+ '});\n\n' +
37
+ 'app.post("/api/login", loginLimiter, async (req, res) => { ... });\n\n' +
38
+ '// For distributed systems use Redis store:\n' +
39
+ 'import RedisStore from "rate-limit-redis";\n' +
40
+ 'const limiter = rateLimit({ store: new RedisStore({ client: redisClient }) });',
41
+ references: [
42
+ 'https://owasp.org/Top10/A04_2021-Insecure_Design/',
43
+ 'https://cwe.mitre.org/data/definitions/770.html',
44
+ 'https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html',
45
+ ],
46
+ tags: ['rate-limiting', 'brute-force', 'auth', 'design'],
47
+ };
48
+ //# sourceMappingURL=missing-rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-rate-limit.js","sourceRoot":"","sources":["../../../src/rules/owasp-a04/missing-rate-limit.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,qDAAqD;AAIrD,MAAM,CAAC,MAAM,gBAAgB,GAAS;IACpC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,6CAA6C;IACnD,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,QAAQ;IAClB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IACvC,WAAW,EACT,uFAAuF;QACvF,wFAAwF;QACxF,qFAAqF;IACvF,QAAQ,EAAE;QACR;YACE,2CAA2C;YAC3C,OAAO,EACL,wJAAwJ;YAC1J,UAAU,EACR,iHAAiH;YACnH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,8CAA8C;YAC9C,OAAO,EACL,iHAAiH;YACnH,UAAU,EACR,oFAAoF;YACtF,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,sEAAsE;QACtE,uCAAuC;QACvC,iDAAiD;QACjD,oCAAoC;QACpC,6CAA6C;QAC7C,uDAAuD;QACvD,8EAA8E;QAC9E,4BAA4B;QAC5B,2BAA2B;QAC3B,SAAS;QACT,wEAAwE;QACxE,+CAA+C;QAC/C,8CAA8C;QAC9C,gFAAgF;IAClF,UAAU,EAAE;QACV,mDAAmD;QACnD,iDAAiD;QACjD,gFAAgF;KACjF;IACD,IAAI,EAAE,CAAC,eAAe,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC;CACzD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const CorsWildcard: Rule;
3
+ //# sourceMappingURL=cors-wildcard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors-wildcard.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a05/cors-wildcard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,YAAY,EAAE,IAiF1B,CAAC"}
@@ -0,0 +1,79 @@
1
+ // OWASP A05:2021 — Security Misconfiguration
2
+ // Rule: CORS wildcard origin — allows any domain to make credentialed requests
3
+ export const CorsWildcard = {
4
+ id: 'OWASP-A05-002',
5
+ name: 'CORS Wildcard Origin (Access-Control-Allow-Origin: *)',
6
+ owasp: 'A05:2021',
7
+ cwe: 'CWE-942',
8
+ severity: 'HIGH',
9
+ languages: ['javascript', 'typescript', 'python', 'php', 'java', 'go', 'ruby'],
10
+ description: 'CORS configured with wildcard origin (*) or reflecting any origin without validation. ' +
11
+ 'Combined with Access-Control-Allow-Credentials: true, this allows any website to make ' +
12
+ 'credentialed cross-origin requests to your API, effectively defeating same-origin protection. ' +
13
+ 'AI tools commonly generate cors() with no options, which defaults to wildcard.',
14
+ patterns: [
15
+ {
16
+ // Express cors() with no arguments (defaults to *) — direct or via require()
17
+ pattern: /app\s*\.\s*use\s*\(\s*(?:require\s*\(\s*['"`]cors['"`]\s*\)\s*\(\s*\)|cors\s*\(\s*\))\s*\)/gi,
18
+ snippetLines: 3,
19
+ },
20
+ {
21
+ // cors({ origin: '*' }) or cors({ origin: true }) — too permissive
22
+ pattern: /cors\s*\(\s*\{\s*[^}]*origin\s*:\s*(?:['"`]\*['"`]|true)\s*[^}]*\}\s*\)/gi,
23
+ snippetLines: 3,
24
+ },
25
+ {
26
+ // Direct header: res.setHeader('Access-Control-Allow-Origin', '*')
27
+ pattern: /(?:res|response)\s*\.\s*(?:setHeader|header)\s*\(\s*['"`]Access-Control-Allow-Origin['"`]\s*,\s*['"`]\*['"`]\s*\)/gi,
28
+ snippetLines: 3,
29
+ },
30
+ {
31
+ // Wildcard + credentials (especially dangerous combination)
32
+ pattern: /Access-Control-Allow-Origin['"]\s*,\s*['"]\*/gi,
33
+ snippetLines: 5,
34
+ },
35
+ {
36
+ // Python Flask-CORS: CORS(app) with no origins restriction
37
+ pattern: /CORS\s*\(\s*app\s*\)/gi,
38
+ suppressIf: /origins\s*=/i,
39
+ snippetLines: 3,
40
+ },
41
+ {
42
+ // Django CORS: CORS_ALLOW_ALL_ORIGINS = True
43
+ pattern: /CORS_ALLOW_ALL_ORIGINS\s*=\s*True/gi,
44
+ snippetLines: 1,
45
+ },
46
+ {
47
+ // Reflecting request origin directly
48
+ pattern: /(?:req|request)\s*\.\s*(?:headers|header)\s*(?:\[['"`]origin['"`]\]|\.origin)\s*\|\|?\s*['"`]\*/gi,
49
+ snippetLines: 3,
50
+ },
51
+ ],
52
+ fix: 'Restrict CORS to a specific allowlist of trusted origins.\n\n' +
53
+ '// Express — explicit origin whitelist:\n' +
54
+ 'import cors from "cors";\n' +
55
+ 'const ALLOWED_ORIGINS = [\n' +
56
+ ' "https://myapp.com",\n' +
57
+ ' "https://www.myapp.com",\n' +
58
+ ' process.env.FRONTEND_URL,\n' +
59
+ '].filter(Boolean);\n\n' +
60
+ 'app.use(cors({\n' +
61
+ ' origin: (origin, callback) => {\n' +
62
+ ' if (!origin || ALLOWED_ORIGINS.includes(origin)) {\n' +
63
+ ' callback(null, true);\n' +
64
+ ' } else {\n' +
65
+ ' callback(new Error("Not allowed by CORS"));\n' +
66
+ ' }\n' +
67
+ ' },\n' +
68
+ ' credentials: true,\n' +
69
+ '}));\n\n' +
70
+ '// Django:\n' +
71
+ 'CORS_ALLOWED_ORIGINS = ["https://myapp.com"] # explicit list',
72
+ references: [
73
+ 'https://owasp.org/Top10/A05_2021-Security_Misconfiguration/',
74
+ 'https://cwe.mitre.org/data/definitions/942.html',
75
+ 'https://cheatsheetseries.owasp.org/cheatsheets/CORS_Cheat_Sheet.html',
76
+ ],
77
+ tags: ['cors', 'misconfiguration', 'cross-origin', 'headers'],
78
+ };
79
+ //# sourceMappingURL=cors-wildcard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors-wildcard.js","sourceRoot":"","sources":["../../../src/rules/owasp-a05/cors-wildcard.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,+EAA+E;AAI/E,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,uDAAuD;IAC7D,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;IAC9E,WAAW,EACT,wFAAwF;QACxF,wFAAwF;QACxF,gGAAgG;QAChG,gFAAgF;IAClF,QAAQ,EAAE;QACR;YACE,6EAA6E;YAC7E,OAAO,EAAE,8FAA8F;YACvG,YAAY,EAAE,CAAC;SAChB;QACD;YACE,mEAAmE;YACnE,OAAO,EACL,2EAA2E;YAC7E,YAAY,EAAE,CAAC;SAChB;QACD;YACE,mEAAmE;YACnE,OAAO,EACL,qHAAqH;YACvH,YAAY,EAAE,CAAC;SAChB;QACD;YACE,4DAA4D;YAC5D,OAAO,EACL,gDAAgD;YAClD,YAAY,EAAE,CAAC;SAChB;QACD;YACE,2DAA2D;YAC3D,OAAO,EAAE,wBAAwB;YACjC,UAAU,EAAE,cAAc;YAC1B,YAAY,EAAE,CAAC;SAChB;QACD;YACE,6CAA6C;YAC7C,OAAO,EAAE,qCAAqC;YAC9C,YAAY,EAAE,CAAC;SAChB;QACD;YACE,qCAAqC;YACrC,OAAO,EACL,mGAAmG;YACrG,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,+DAA+D;QAC/D,2CAA2C;QAC3C,4BAA4B;QAC5B,6BAA6B;QAC7B,0BAA0B;QAC1B,8BAA8B;QAC9B,+BAA+B;QAC/B,wBAAwB;QACxB,kBAAkB;QAClB,qCAAqC;QACrC,0DAA0D;QAC1D,+BAA+B;QAC/B,gBAAgB;QAChB,qDAAqD;QACrD,SAAS;QACT,QAAQ;QACR,wBAAwB;QACxB,UAAU;QACV,cAAc;QACd,+DAA+D;IACjE,UAAU,EAAE;QACV,6DAA6D;QAC7D,iDAAiD;QACjD,sEAAsE;KACvE;IACD,IAAI,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,SAAS,CAAC;CAC9D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const DebugMode: Rule;
3
+ //# sourceMappingURL=debug-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-mode.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a05/debug-mode.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,SAAS,EAAE,IAuEvB,CAAC"}
@@ -0,0 +1,73 @@
1
+ // OWASP A05:2021 — Security Misconfiguration
2
+ // Rule: Debug mode enabled in production configuration
3
+ export const DebugMode = {
4
+ id: 'OWASP-A05-001',
5
+ name: 'Debug Mode Enabled in Production',
6
+ owasp: 'A05:2021',
7
+ cwe: 'CWE-94',
8
+ severity: 'HIGH',
9
+ languages: ['javascript', 'typescript', 'python', 'php', 'java', 'ruby'],
10
+ description: 'Debug mode or development environment settings left active in production code. ' +
11
+ 'This exposes stack traces, internal paths, environment variables, and source code ' +
12
+ 'to users — providing attackers with valuable reconnaissance information. ' +
13
+ 'AI tools commonly generate DEBUG=True from tutorial templates.',
14
+ patterns: [
15
+ {
16
+ // Python/Django: DEBUG = True in settings file
17
+ pattern: /\bDEBUG\s*=\s*True\b/g,
18
+ suppressIf: /(?:test|spec|debug_setting|if.*DEBUG|DEBUG_OVERRIDE|dev|development)/i,
19
+ snippetLines: 1,
20
+ },
21
+ {
22
+ // Flask: app.run(debug=True) or app.debug = True
23
+ pattern: /(?:app\.run\s*\([^)]*debug\s*=\s*True|app\.debug\s*=\s*True)/gi,
24
+ snippetLines: 3,
25
+ },
26
+ {
27
+ // Node.js: NODE_ENV = development (hardcoded)
28
+ pattern: /NODE_ENV\s*=\s*['"`]development['"`]/g,
29
+ suppressIf: /(?:test|spec|dev-only|if.*NODE_ENV)/i,
30
+ snippetLines: 1,
31
+ },
32
+ {
33
+ // Express: app.set('env', 'development')
34
+ pattern: /app\s*\.\s*set\s*\(\s*['"`]env['"`]\s*,\s*['"`]development['"`]\s*\)/gi,
35
+ snippetLines: 3,
36
+ },
37
+ {
38
+ // PHP: ini_set('display_errors', '1') or error_reporting(E_ALL)
39
+ pattern: /ini_set\s*\(\s*['"`]display_errors['"`]\s*,\s*['"`]?1['"`]?\s*\)/gi,
40
+ snippetLines: 3,
41
+ },
42
+ {
43
+ // Spring Boot: spring.jpa.show-sql=true or logging.level=DEBUG
44
+ pattern: /(?:spring\.jpa\.show-sql\s*=\s*true|logging\.level\s*=\s*DEBUG)/gi,
45
+ snippetLines: 1,
46
+ },
47
+ {
48
+ // Generic: verbose error output to client
49
+ pattern: /res\s*\.\s*(?:send|json)\s*\([^)]*(?:error\.stack|err\.stack|e\.stack)\s*\)/gi,
50
+ snippetLines: 3,
51
+ },
52
+ ],
53
+ fix: 'Use environment variables to control debug settings. Never hardcode debug=true.\n\n' +
54
+ '// Python/Django:\n' +
55
+ 'DEBUG = os.environ.get("DEBUG", "False") == "True" # False in production\n\n' +
56
+ '// Flask:\n' +
57
+ 'app.run(debug=os.environ.get("FLASK_DEBUG", "0") == "1")\n\n' +
58
+ '// Node.js — never expose stack traces:\n' +
59
+ 'app.use((err, req, res, next) => {\n' +
60
+ ' const isDev = process.env.NODE_ENV === "development";\n' +
61
+ ' res.status(500).json({\n' +
62
+ ' error: "Internal Server Error",\n' +
63
+ ' ...(isDev && { stack: err.stack }), // only in dev\n' +
64
+ ' });\n' +
65
+ '});',
66
+ references: [
67
+ 'https://owasp.org/Top10/A05_2021-Security_Misconfiguration/',
68
+ 'https://cwe.mitre.org/data/definitions/94.html',
69
+ 'https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html',
70
+ ],
71
+ tags: ['misconfiguration', 'debug', 'information-disclosure', 'production'],
72
+ };
73
+ //# sourceMappingURL=debug-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-mode.js","sourceRoot":"","sources":["../../../src/rules/owasp-a05/debug-mode.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,uDAAuD;AAIvD,MAAM,CAAC,MAAM,SAAS,GAAS;IAC7B,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,kCAAkC;IACxC,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,QAAQ;IACb,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;IACxE,WAAW,EACT,iFAAiF;QACjF,oFAAoF;QACpF,2EAA2E;QAC3E,gEAAgE;IAClE,QAAQ,EAAE;QACR;YACE,+CAA+C;YAC/C,OAAO,EAAE,uBAAuB;YAChC,UAAU,EAAE,uEAAuE;YACnF,YAAY,EAAE,CAAC;SAChB;QACD;YACE,iDAAiD;YACjD,OAAO,EAAE,gEAAgE;YACzE,YAAY,EAAE,CAAC;SAChB;QACD;YACE,8CAA8C;YAC9C,OAAO,EAAE,uCAAuC;YAChD,UAAU,EAAE,sCAAsC;YAClD,YAAY,EAAE,CAAC;SAChB;QACD;YACE,yCAAyC;YACzC,OAAO,EAAE,wEAAwE;YACjF,YAAY,EAAE,CAAC;SAChB;QACD;YACE,gEAAgE;YAChE,OAAO,EAAE,oEAAoE;YAC7E,YAAY,EAAE,CAAC;SAChB;QACD;YACE,+DAA+D;YAC/D,OAAO,EAAE,mEAAmE;YAC5E,YAAY,EAAE,CAAC;SAChB;QACD;YACE,0CAA0C;YAC1C,OAAO,EAAE,+EAA+E;YACxF,YAAY,EAAE,CAAC;SAChB;KACF;IACD,GAAG,EACD,qFAAqF;QACrF,qBAAqB;QACrB,+EAA+E;QAC/E,aAAa;QACb,8DAA8D;QAC9D,2CAA2C;QAC3C,sCAAsC;QACtC,2DAA2D;QAC3D,4BAA4B;QAC5B,uCAAuC;QACvC,0DAA0D;QAC1D,SAAS;QACT,KAAK;IACP,UAAU,EAAE;QACV,6DAA6D;QAC7D,gDAAgD;QAChD,gFAAgF;KACjF;IACD,IAAI,EAAE,CAAC,kBAAkB,EAAE,OAAO,EAAE,wBAAwB,EAAE,YAAY,CAAC;CAC5E,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../types/index.js';
2
+ export declare const DefaultCredentials: Rule;
3
+ //# sourceMappingURL=default-credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-credentials.d.ts","sourceRoot":"","sources":["../../../src/rules/owasp-a05/default-credentials.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,eAAO,MAAM,kBAAkB,EAAE,IAsDhC,CAAC"}