@datahogo/core 0.1.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 (153) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +17 -0
  3. package/dist/engines/config.d.ts +3 -0
  4. package/dist/engines/config.d.ts.map +1 -0
  5. package/dist/engines/config.js +433 -0
  6. package/dist/engines/config.js.map +1 -0
  7. package/dist/engines/dast.d.ts +3 -0
  8. package/dist/engines/dast.d.ts.map +1 -0
  9. package/dist/engines/dast.js +167 -0
  10. package/dist/engines/dast.js.map +1 -0
  11. package/dist/engines/db-rules.d.ts +3 -0
  12. package/dist/engines/db-rules.d.ts.map +1 -0
  13. package/dist/engines/db-rules.js +166 -0
  14. package/dist/engines/db-rules.js.map +1 -0
  15. package/dist/engines/dependencies.d.ts +3 -0
  16. package/dist/engines/dependencies.d.ts.map +1 -0
  17. package/dist/engines/dependencies.js +167 -0
  18. package/dist/engines/dependencies.js.map +1 -0
  19. package/dist/engines/github-actions.d.ts +3 -0
  20. package/dist/engines/github-actions.d.ts.map +1 -0
  21. package/dist/engines/github-actions.js +215 -0
  22. package/dist/engines/github-actions.js.map +1 -0
  23. package/dist/engines/gitleaks.d.ts +3 -0
  24. package/dist/engines/gitleaks.d.ts.map +1 -0
  25. package/dist/engines/gitleaks.js +107 -0
  26. package/dist/engines/gitleaks.js.map +1 -0
  27. package/dist/engines/npm-audit.d.ts +3 -0
  28. package/dist/engines/npm-audit.d.ts.map +1 -0
  29. package/dist/engines/npm-audit.js +113 -0
  30. package/dist/engines/npm-audit.js.map +1 -0
  31. package/dist/engines/patterns.d.ts +3 -0
  32. package/dist/engines/patterns.d.ts.map +1 -0
  33. package/dist/engines/patterns.js +1330 -0
  34. package/dist/engines/patterns.js.map +1 -0
  35. package/dist/engines/secrets.d.ts +4 -0
  36. package/dist/engines/secrets.d.ts.map +1 -0
  37. package/dist/engines/secrets.js +260 -0
  38. package/dist/engines/secrets.js.map +1 -0
  39. package/dist/engines/semgrep.d.ts +3 -0
  40. package/dist/engines/semgrep.d.ts.map +1 -0
  41. package/dist/engines/semgrep.js +173 -0
  42. package/dist/engines/semgrep.js.map +1 -0
  43. package/dist/engines/types.d.ts +30 -0
  44. package/dist/engines/types.d.ts.map +1 -0
  45. package/dist/engines/types.js +3 -0
  46. package/dist/engines/types.js.map +1 -0
  47. package/dist/engines/url-scanner.d.ts +3 -0
  48. package/dist/engines/url-scanner.d.ts.map +1 -0
  49. package/dist/engines/url-scanner.js +469 -0
  50. package/dist/engines/url-scanner.js.map +1 -0
  51. package/dist/index.d.ts +8 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +8 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/orchestrator.d.ts +32 -0
  56. package/dist/orchestrator.d.ts.map +1 -0
  57. package/dist/orchestrator.js +237 -0
  58. package/dist/orchestrator.js.map +1 -0
  59. package/dist/rules/.gitkeep +0 -0
  60. package/dist/rules/ai-llm-security.yaml +199 -0
  61. package/dist/rules/api-security.yaml +489 -0
  62. package/dist/rules/auth-patterns.yaml +406 -0
  63. package/dist/rules/crypto-patterns.yaml +227 -0
  64. package/dist/rules/database-cloud-security.yaml +169 -0
  65. package/dist/rules/general-security.yaml +588 -0
  66. package/dist/rules/injection-patterns.yaml +318 -0
  67. package/dist/rules/nextjs-security.yaml +532 -0
  68. package/dist/rules/node-security.yaml +380 -0
  69. package/dist/rules/rules/.gitkeep +0 -0
  70. package/dist/rules/rules/ai-llm-security.yaml +199 -0
  71. package/dist/rules/rules/api-security.yaml +489 -0
  72. package/dist/rules/rules/auth-patterns.yaml +406 -0
  73. package/dist/rules/rules/crypto-patterns.yaml +227 -0
  74. package/dist/rules/rules/database-cloud-security.yaml +169 -0
  75. package/dist/rules/rules/general-security.yaml +588 -0
  76. package/dist/rules/rules/injection-patterns.yaml +318 -0
  77. package/dist/rules/rules/nextjs-security.yaml +532 -0
  78. package/dist/rules/rules/node-security.yaml +380 -0
  79. package/dist/rules/rules/supabase-security.yaml +387 -0
  80. package/dist/rules/supabase-security.yaml +387 -0
  81. package/dist/scanning/agents/csharp-agent.d.ts +12 -0
  82. package/dist/scanning/agents/csharp-agent.d.ts.map +1 -0
  83. package/dist/scanning/agents/csharp-agent.js +592 -0
  84. package/dist/scanning/agents/csharp-agent.js.map +1 -0
  85. package/dist/scanning/agents/go-agent.d.ts +14 -0
  86. package/dist/scanning/agents/go-agent.d.ts.map +1 -0
  87. package/dist/scanning/agents/go-agent.js +641 -0
  88. package/dist/scanning/agents/go-agent.js.map +1 -0
  89. package/dist/scanning/agents/java-agent.d.ts +8 -0
  90. package/dist/scanning/agents/java-agent.d.ts.map +1 -0
  91. package/dist/scanning/agents/java-agent.js +807 -0
  92. package/dist/scanning/agents/java-agent.js.map +1 -0
  93. package/dist/scanning/agents/javascript-agent.d.ts +8 -0
  94. package/dist/scanning/agents/javascript-agent.d.ts.map +1 -0
  95. package/dist/scanning/agents/javascript-agent.js +77 -0
  96. package/dist/scanning/agents/javascript-agent.js.map +1 -0
  97. package/dist/scanning/agents/mobile-agent.d.ts +8 -0
  98. package/dist/scanning/agents/mobile-agent.d.ts.map +1 -0
  99. package/dist/scanning/agents/mobile-agent.js +916 -0
  100. package/dist/scanning/agents/mobile-agent.js.map +1 -0
  101. package/dist/scanning/agents/php-agent.d.ts +8 -0
  102. package/dist/scanning/agents/php-agent.d.ts.map +1 -0
  103. package/dist/scanning/agents/php-agent.js +679 -0
  104. package/dist/scanning/agents/php-agent.js.map +1 -0
  105. package/dist/scanning/agents/python-agent.d.ts +8 -0
  106. package/dist/scanning/agents/python-agent.d.ts.map +1 -0
  107. package/dist/scanning/agents/python-agent.js +701 -0
  108. package/dist/scanning/agents/python-agent.js.map +1 -0
  109. package/dist/scanning/agents/supabase-agent.d.ts +8 -0
  110. package/dist/scanning/agents/supabase-agent.d.ts.map +1 -0
  111. package/dist/scanning/agents/supabase-agent.js +484 -0
  112. package/dist/scanning/agents/supabase-agent.js.map +1 -0
  113. package/dist/scanning/orchestrator.d.ts +29 -0
  114. package/dist/scanning/orchestrator.d.ts.map +1 -0
  115. package/dist/scanning/orchestrator.js +186 -0
  116. package/dist/scanning/orchestrator.js.map +1 -0
  117. package/dist/scanning/tech-detector.d.ts +12 -0
  118. package/dist/scanning/tech-detector.d.ts.map +1 -0
  119. package/dist/scanning/tech-detector.js +252 -0
  120. package/dist/scanning/tech-detector.js.map +1 -0
  121. package/dist/scanning/types.d.ts +87 -0
  122. package/dist/scanning/types.d.ts.map +1 -0
  123. package/dist/scanning/types.js +5 -0
  124. package/dist/scanning/types.js.map +1 -0
  125. package/dist/utils/child-process.d.ts +2 -0
  126. package/dist/utils/child-process.d.ts.map +1 -0
  127. package/dist/utils/child-process.js +4 -0
  128. package/dist/utils/child-process.js.map +1 -0
  129. package/dist/utils/context-classifier.d.ts +11 -0
  130. package/dist/utils/context-classifier.d.ts.map +1 -0
  131. package/dist/utils/context-classifier.js +79 -0
  132. package/dist/utils/context-classifier.js.map +1 -0
  133. package/dist/utils/exec.d.ts +18 -0
  134. package/dist/utils/exec.d.ts.map +1 -0
  135. package/dist/utils/exec.js +51 -0
  136. package/dist/utils/exec.js.map +1 -0
  137. package/dist/utils/file-filter.d.ts +4 -0
  138. package/dist/utils/file-filter.d.ts.map +1 -0
  139. package/dist/utils/file-filter.js +68 -0
  140. package/dist/utils/file-filter.js.map +1 -0
  141. package/dist/utils/fs.d.ts +2 -0
  142. package/dist/utils/fs.d.ts.map +1 -0
  143. package/dist/utils/fs.js +5 -0
  144. package/dist/utils/fs.js.map +1 -0
  145. package/dist/utils/logger.d.ts +12 -0
  146. package/dist/utils/logger.d.ts.map +1 -0
  147. package/dist/utils/logger.js +27 -0
  148. package/dist/utils/logger.js.map +1 -0
  149. package/dist/utils/post-processor.d.ts +10 -0
  150. package/dist/utils/post-processor.d.ts.map +1 -0
  151. package/dist/utils/post-processor.js +183 -0
  152. package/dist/utils/post-processor.js.map +1 -0
  153. package/package.json +44 -0
@@ -0,0 +1,489 @@
1
+ rules:
2
+ # ID 21: BOLA - Broken Object Level Authorization
3
+ - id: datahogo-api-bola-no-ownership-check
4
+ patterns:
5
+ - pattern-either:
6
+ - pattern: |
7
+ export async function $METHOD(req: Request, { params }: { params: { $ID: string } }) {
8
+ ...
9
+ $DB.$QUERY({ where: { id: params.$ID } })
10
+ ...
11
+ }
12
+ - pattern: |
13
+ export async function $METHOD(req: Request) {
14
+ ...
15
+ const $ID = $GETID
16
+ ...
17
+ $DB.$QUERY({ where: { id: $ID } })
18
+ ...
19
+ }
20
+ - pattern-not: |
21
+ export async function $METHOD(req: Request, ...) {
22
+ ...
23
+ $CLIENT.auth.getUser()
24
+ ...
25
+ $DB.$QUERY({ where: { id: $ID, userId: $USERID } })
26
+ ...
27
+ }
28
+ - pattern-not-inside: |
29
+ if (!$USER || $ITEM.userId !== $USER.id) {
30
+ ...
31
+ }
32
+ message: "API endpoint accesses resource by ID without verifying user ownership. This can lead to unauthorized access (BOLA/IDOR)."
33
+ severity: ERROR
34
+ languages: [typescript, javascript]
35
+ metadata:
36
+ datahogo_id: 21
37
+ datahogo_category: "api"
38
+ owasp_ref: "API1:2023"
39
+
40
+ # ID 22: Broken Authentication - JWT without validation
41
+ - id: datahogo-api-jwt-decode-only
42
+ pattern: |
43
+ jwt.decode($TOKEN)
44
+ message: "jwt.decode() does not verify the token signature. Use jwt.verify() for secure authentication."
45
+ severity: ERROR
46
+ languages: [typescript, javascript]
47
+ metadata:
48
+ datahogo_id: 22
49
+ datahogo_category: "api"
50
+ owasp_ref: "API2:2023"
51
+
52
+ - id: datahogo-api-jwt-no-expiry
53
+ patterns:
54
+ - pattern: |
55
+ jwt.sign($PAYLOAD, $SECRET)
56
+ - pattern-not: |
57
+ jwt.sign($PAYLOAD, $SECRET, { expiresIn: $EXPIRY, ... })
58
+ - pattern-not: |
59
+ jwt.sign({ ..., exp: $EXP }, $SECRET, ...)
60
+ message: "JWT token created without expiration time. Tokens should expire to limit exposure from theft."
61
+ severity: ERROR
62
+ languages: [typescript, javascript]
63
+ metadata:
64
+ datahogo_id: 22
65
+ datahogo_category: "api"
66
+ owasp_ref: "API2:2023"
67
+
68
+ - id: datahogo-api-bearer-token-in-url
69
+ patterns:
70
+ - pattern-either:
71
+ - pattern: "$URL + '?token=' + $TOKEN"
72
+ - pattern: "`${$URL}?token=${$TOKEN}`"
73
+ - pattern: "$URL + '&token=' + $TOKEN"
74
+ - pattern: "`${$URL}&token=${$TOKEN}`"
75
+ message: "Bearer token passed in URL query parameter. Tokens should be sent in Authorization header to prevent logging/leaking."
76
+ severity: ERROR
77
+ languages: [typescript, javascript]
78
+ metadata:
79
+ datahogo_id: 22
80
+ datahogo_category: "api"
81
+ owasp_ref: "API2:2023"
82
+
83
+ # ID 23: Broken Object Property Authorization - Mass Assignment
84
+ - id: datahogo-api-mass-assignment-spread
85
+ patterns:
86
+ - pattern-either:
87
+ - pattern: |
88
+ $DB.$TABLE.update({ where: { id: $ID }, data: { ...$REQ.body } })
89
+ - pattern: |
90
+ $DB.$TABLE.create({ data: { ...$REQ.body } })
91
+ - pattern: |
92
+ $DB.$TABLE.update({ where: { id: $ID }, data: $REQ.body })
93
+ - pattern: |
94
+ $DB.$TABLE.create({ data: $REQ.body })
95
+ - pattern-not-inside: |
96
+ const { $ALLOWED, ... } = $REQ.body
97
+ ...
98
+ message: "Mass assignment vulnerability: request body spread directly into database update. Whitelist allowed fields to prevent unauthorized property changes."
99
+ severity: WARNING
100
+ languages: [typescript, javascript]
101
+ metadata:
102
+ datahogo_id: 23
103
+ datahogo_category: "api"
104
+ owasp_ref: "API3:2023"
105
+
106
+ - id: datahogo-api-mass-assignment-role
107
+ patterns:
108
+ - pattern-either:
109
+ - pattern: |
110
+ $DB.user.update({ data: { ...$DATA, role: $ROLE } })
111
+ - pattern: |
112
+ $DB.user.update({ data: { role: $REQ.body.role } })
113
+ message: "User role being set from request data. This allows privilege escalation. Only admins should update roles."
114
+ severity: ERROR
115
+ languages: [typescript, javascript]
116
+ metadata:
117
+ datahogo_id: 23
118
+ datahogo_category: "api"
119
+ owasp_ref: "API3:2023"
120
+
121
+ # ID 24: Unrestricted Resource Consumption - No rate limiting
122
+ - id: datahogo-api-no-rate-limit-express
123
+ patterns:
124
+ - pattern: |
125
+ $APP.$METHOD($PATH, async ($REQ, $RES) => { ... })
126
+ - pattern-not-inside: |
127
+ $APP.use(..., rateLimit(...), ...)
128
+ - pattern-not-inside: |
129
+ $APP.$METHOD($PATH, rateLimit(...), async ($REQ, $RES) => { ... })
130
+ message: "API route has no rate limiting middleware. Add rate limiting to prevent abuse and resource exhaustion."
131
+ severity: WARNING
132
+ languages: [typescript, javascript]
133
+ metadata:
134
+ datahogo_id: 24
135
+ datahogo_category: "api"
136
+ owasp_ref: "API4:2023"
137
+
138
+ - id: datahogo-api-no-rate-limit-nextjs
139
+ patterns:
140
+ - pattern: |
141
+ export async function POST(req: Request) {
142
+ ...
143
+ }
144
+ - pattern-not-inside: |
145
+ const $LIMITER = new Ratelimit(...)
146
+ ...
147
+ await $LIMITER.limit(...)
148
+ - metavariable-regex:
149
+ metavariable: $CONTENT
150
+ regex: "(login|register|reset|forgot|verify|otp|mfa|2fa)"
151
+ message: "Authentication endpoint missing rate limiting. Add rate limiting to prevent brute force attacks."
152
+ severity: ERROR
153
+ languages: [typescript, javascript]
154
+ metadata:
155
+ datahogo_id: 24
156
+ datahogo_category: "api"
157
+ owasp_ref: "API4:2023"
158
+
159
+ # ID 25: Broken Function Level Authorization - Admin endpoints without role check
160
+ - id: datahogo-api-admin-no-role-check
161
+ patterns:
162
+ - pattern-either:
163
+ - pattern: |
164
+ export async function $METHOD(req: Request) {
165
+ ...
166
+ }
167
+ - pattern: |
168
+ $APP.$METHOD('/admin/...', async ($REQ, $RES) => {
169
+ ...
170
+ })
171
+ - metavariable-regex:
172
+ metavariable: $METHOD
173
+ regex: "(DELETE|POST|PUT|PATCH)"
174
+ - pattern-not-inside: |
175
+ if ($USER.role !== 'admin') {
176
+ ...
177
+ }
178
+ - pattern-not-inside: |
179
+ if (!$USER.isAdmin) {
180
+ ...
181
+ }
182
+ message: "Admin or privileged endpoint missing role-based access control. Verify user role before allowing access."
183
+ severity: ERROR
184
+ languages: [typescript, javascript]
185
+ metadata:
186
+ datahogo_id: 25
187
+ datahogo_category: "api"
188
+ owasp_ref: "API5:2023"
189
+
190
+ - id: datahogo-api-delete-no-auth
191
+ patterns:
192
+ - pattern: |
193
+ export async function DELETE(req: Request, { params }: { params: { $ID: string } }) {
194
+ ...
195
+ $DB.$TABLE.delete({ where: { id: params.$ID } })
196
+ ...
197
+ }
198
+ - pattern-not: |
199
+ export async function DELETE(req: Request, { params }: { params: { $ID: string } }) {
200
+ ...
201
+ const { data: { user } } = await $CLIENT.auth.getUser()
202
+ ...
203
+ $DB.$TABLE.delete({ where: { id: params.$ID, userId: user.id } })
204
+ ...
205
+ }
206
+ message: "DELETE endpoint allows deletion without verifying ownership or admin role. Add authorization check."
207
+ severity: ERROR
208
+ languages: [typescript, javascript]
209
+ metadata:
210
+ datahogo_id: 25
211
+ datahogo_category: "api"
212
+ owasp_ref: "API5:2023"
213
+
214
+ # ID 27: SSRF in API - fetch with user-controlled URL
215
+ - id: datahogo-api-ssrf-fetch
216
+ patterns:
217
+ - pattern-either:
218
+ - pattern: |
219
+ fetch($REQ.body.$URL)
220
+ - pattern: |
221
+ fetch($REQ.query.$URL)
222
+ - pattern: |
223
+ axios.get($REQ.body.$URL)
224
+ - pattern: |
225
+ axios($REQ.body.$URL)
226
+ - pattern: |
227
+ fetch(`${$REQ.body.$PATH}`)
228
+ - pattern-not-inside: |
229
+ if (!$ALLOWED_URLS.includes($URL)) {
230
+ ...
231
+ }
232
+ - pattern-not-inside: |
233
+ if (!$URL.startsWith('https://')) {
234
+ ...
235
+ }
236
+ message: "Server-Side Request Forgery (SSRF): fetch/axios called with user-controlled URL. Validate URL against allowlist."
237
+ severity: ERROR
238
+ languages: [typescript, javascript]
239
+ metadata:
240
+ datahogo_id: 27
241
+ datahogo_category: "api"
242
+ owasp_ref: "API7:2023"
243
+
244
+ # ID 28: Verbose errors returned to client
245
+ - id: datahogo-api-verbose-error
246
+ patterns:
247
+ - pattern-either:
248
+ - pattern: |
249
+ return Response.json({ error: $ERR.message, stack: $ERR.stack }, ...)
250
+ - pattern: |
251
+ return Response.json({ ..., stack: $ERR.stack }, ...)
252
+ - pattern: |
253
+ return $RES.status($CODE).json({ error: $ERR, ... })
254
+ - pattern: |
255
+ return $RES.json({ error: $ERR.stack, ... })
256
+ message: "Verbose error details (stack trace or full error object) exposed to client. Return generic error message instead."
257
+ severity: WARNING
258
+ languages: [typescript, javascript]
259
+ metadata:
260
+ datahogo_id: 28
261
+ datahogo_category: "api"
262
+ owasp_ref: "API8:2023"
263
+
264
+ - id: datahogo-api-error-db-details
265
+ patterns:
266
+ - pattern: |
267
+ catch ($ERR) {
268
+ ...
269
+ return Response.json({ error: $ERR.message }, ...)
270
+ ...
271
+ }
272
+ - metavariable-regex:
273
+ metavariable: $ERR
274
+ regex: "(dbError|queryError|sqlError|prismaError)"
275
+ message: "Database error message returned to client. This may leak schema information. Return generic error instead."
276
+ severity: WARNING
277
+ languages: [typescript, javascript]
278
+ metadata:
279
+ datahogo_id: 28
280
+ datahogo_category: "api"
281
+ owasp_ref: "API8:2023"
282
+
283
+ # ID 30: Unsafe API consumption - trusting external API without validation
284
+ - id: datahogo-api-unsafe-external-response
285
+ patterns:
286
+ - pattern: |
287
+ const $RESPONSE = await fetch($EXTERNAL_URL)
288
+ const $DATA = await $RESPONSE.json()
289
+ ...
290
+ $DB.$TABLE.create({ data: $DATA })
291
+ - pattern-not-inside: |
292
+ const $SCHEMA = z.object(...)
293
+ ...
294
+ $SCHEMA.parse($DATA)
295
+ message: "External API response used without validation. Validate schema with Zod before using or storing data."
296
+ severity: WARNING
297
+ languages: [typescript, javascript]
298
+ metadata:
299
+ datahogo_id: 30
300
+ datahogo_category: "api"
301
+ owasp_ref: "API10:2023"
302
+
303
+ # ID 94: API docs exposed in production
304
+ - id: datahogo-api-docs-route
305
+ patterns:
306
+ - pattern-either:
307
+ - pattern: |
308
+ $APP.use('/swagger', ...)
309
+ - pattern: |
310
+ $APP.use('/api-docs', ...)
311
+ - pattern: |
312
+ $APP.get('/docs', ...)
313
+ - pattern: |
314
+ $APP.use('/graphql', graphiql: true, ...)
315
+ - pattern-not-inside: |
316
+ if (process.env.NODE_ENV === 'development') {
317
+ ...
318
+ }
319
+ message: "API documentation endpoint exposed without environment check. Restrict to development only."
320
+ severity: WARNING
321
+ languages: [typescript, javascript]
322
+ metadata:
323
+ datahogo_id: 94
324
+ datahogo_category: "api"
325
+ owasp_ref: "API9:2023"
326
+
327
+ # ID 96: GraphQL query depth - no depth limit
328
+ - id: datahogo-api-graphql-no-depth-limit
329
+ patterns:
330
+ - pattern: |
331
+ new ApolloServer({ ... })
332
+ - pattern-not: |
333
+ new ApolloServer({
334
+ ...
335
+ validationRules: [..., depthLimit($LIMIT), ...],
336
+ ...
337
+ })
338
+ message: "GraphQL server without query depth limit. Add depth limiting to prevent resource exhaustion attacks."
339
+ severity: WARNING
340
+ languages: [typescript, javascript]
341
+ metadata:
342
+ datahogo_id: 96
343
+ datahogo_category: "api"
344
+ owasp_ref: "API4:2023"
345
+
346
+ # ID 97: GraphQL batching attack - no batch size limit
347
+ - id: datahogo-api-graphql-no-batch-limit
348
+ patterns:
349
+ - pattern: |
350
+ new ApolloServer({ ... })
351
+ - pattern-not: |
352
+ new ApolloServer({
353
+ ...
354
+ plugins: [..., ApolloServerPluginLandingPageDisabled(), ...],
355
+ ...
356
+ })
357
+ - pattern-not-inside: |
358
+ if ($ARRAY.length > $LIMIT) {
359
+ ...
360
+ }
361
+ message: "GraphQL server may be vulnerable to batching attacks. Implement query batch size limits."
362
+ severity: WARNING
363
+ languages: [typescript, javascript]
364
+ metadata:
365
+ datahogo_id: 97
366
+ datahogo_category: "api"
367
+ owasp_ref: "API4:2023"
368
+
369
+ # ID 100: API key scope too broad
370
+ - id: datahogo-api-key-admin-operations
371
+ patterns:
372
+ - pattern-either:
373
+ - pattern: |
374
+ const $CLIENT = createClient($URL, process.env.SUPABASE_SERVICE_ROLE_KEY)
375
+ - pattern: |
376
+ Authorization: 'Bearer ' + process.env.ADMIN_API_KEY
377
+ - pattern-not-inside: |
378
+ // Service role required for $REASON
379
+ ...
380
+ - pattern-not-inside: |
381
+ // Admin key needed for $REASON
382
+ ...
383
+ message: "Admin/service role API key used without justification comment. Use least-privilege keys when possible."
384
+ severity: WARNING
385
+ languages: [typescript, javascript]
386
+ metadata:
387
+ datahogo_id: 100
388
+ datahogo_category: "api"
389
+ owasp_ref: "API8:2023"
390
+
391
+ # ID 196: No request body limit
392
+ - id: datahogo-api-no-body-limit-express
393
+ patterns:
394
+ - pattern: |
395
+ $APP.use(express.json())
396
+ - pattern-not: |
397
+ $APP.use(express.json({ limit: $LIMIT }))
398
+ message: "express.json() middleware without body size limit. Add limit to prevent resource exhaustion (e.g., { limit: '1mb' })."
399
+ severity: WARNING
400
+ languages: [typescript, javascript]
401
+ metadata:
402
+ datahogo_id: 196
403
+ datahogo_category: "api"
404
+ owasp_ref: "API4:2023"
405
+
406
+ # ID 197: No rate limiting middleware
407
+ - id: datahogo-api-missing-global-rate-limit
408
+ patterns:
409
+ - pattern: |
410
+ const $APP = express()
411
+ ...
412
+ $APP.listen($PORT)
413
+ - pattern-not: |
414
+ const $APP = express()
415
+ ...
416
+ $APP.use(rateLimit(...))
417
+ ...
418
+ $APP.listen($PORT)
419
+ message: "Express app without global rate limiting middleware. Add rate limiting to prevent abuse."
420
+ severity: WARNING
421
+ languages: [typescript, javascript]
422
+ metadata:
423
+ datahogo_id: 197
424
+ datahogo_category: "api"
425
+ owasp_ref: "API4:2023"
426
+
427
+ # ID 198: No request timeout
428
+ - id: datahogo-api-no-timeout
429
+ patterns:
430
+ - pattern-either:
431
+ - pattern: |
432
+ fetch($URL)
433
+ - pattern: |
434
+ axios.get($URL)
435
+ - pattern: |
436
+ axios.post($URL, $DATA)
437
+ - pattern-not: |
438
+ fetch($URL, { signal: AbortSignal.timeout($MS) })
439
+ - pattern-not: |
440
+ axios.get($URL, { timeout: $MS })
441
+ - pattern-not: |
442
+ axios.post($URL, $DATA, { timeout: $MS })
443
+ - pattern-inside: |
444
+ export async function $METHOD(req: Request) {
445
+ ...
446
+ }
447
+ message: "HTTP request in API handler without timeout. Add timeout to prevent hung requests from exhausting resources."
448
+ severity: WARNING
449
+ languages: [typescript, javascript]
450
+ metadata:
451
+ datahogo_id: 198
452
+ datahogo_category: "api"
453
+ owasp_ref: "API4:2023"
454
+
455
+ # ID 199: WebSocket without auth
456
+ - id: datahogo-api-websocket-no-auth
457
+ patterns:
458
+ - pattern-either:
459
+ - pattern: |
460
+ $WS.on('connection', ($SOCKET) => {
461
+ ...
462
+ })
463
+ - pattern: |
464
+ io.on('connection', ($SOCKET) => {
465
+ ...
466
+ })
467
+ - pattern-not: |
468
+ $WS.on('connection', ($SOCKET) => {
469
+ ...
470
+ if (!$SOCKET.handshake.auth.$TOKEN) {
471
+ ...
472
+ }
473
+ ...
474
+ })
475
+ - pattern-not: |
476
+ io.on('connection', ($SOCKET) => {
477
+ ...
478
+ if (!$SOCKET.handshake.auth.$TOKEN) {
479
+ ...
480
+ }
481
+ ...
482
+ })
483
+ message: "WebSocket connection handler without authentication check. Verify user identity before allowing connections."
484
+ severity: ERROR
485
+ languages: [typescript, javascript]
486
+ metadata:
487
+ datahogo_id: 199
488
+ datahogo_category: "api"
489
+ owasp_ref: "API2:2023"