@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.
- package/LICENSE +661 -0
- package/README.md +17 -0
- package/dist/engines/config.d.ts +3 -0
- package/dist/engines/config.d.ts.map +1 -0
- package/dist/engines/config.js +433 -0
- package/dist/engines/config.js.map +1 -0
- package/dist/engines/dast.d.ts +3 -0
- package/dist/engines/dast.d.ts.map +1 -0
- package/dist/engines/dast.js +167 -0
- package/dist/engines/dast.js.map +1 -0
- package/dist/engines/db-rules.d.ts +3 -0
- package/dist/engines/db-rules.d.ts.map +1 -0
- package/dist/engines/db-rules.js +166 -0
- package/dist/engines/db-rules.js.map +1 -0
- package/dist/engines/dependencies.d.ts +3 -0
- package/dist/engines/dependencies.d.ts.map +1 -0
- package/dist/engines/dependencies.js +167 -0
- package/dist/engines/dependencies.js.map +1 -0
- package/dist/engines/github-actions.d.ts +3 -0
- package/dist/engines/github-actions.d.ts.map +1 -0
- package/dist/engines/github-actions.js +215 -0
- package/dist/engines/github-actions.js.map +1 -0
- package/dist/engines/gitleaks.d.ts +3 -0
- package/dist/engines/gitleaks.d.ts.map +1 -0
- package/dist/engines/gitleaks.js +107 -0
- package/dist/engines/gitleaks.js.map +1 -0
- package/dist/engines/npm-audit.d.ts +3 -0
- package/dist/engines/npm-audit.d.ts.map +1 -0
- package/dist/engines/npm-audit.js +113 -0
- package/dist/engines/npm-audit.js.map +1 -0
- package/dist/engines/patterns.d.ts +3 -0
- package/dist/engines/patterns.d.ts.map +1 -0
- package/dist/engines/patterns.js +1330 -0
- package/dist/engines/patterns.js.map +1 -0
- package/dist/engines/secrets.d.ts +4 -0
- package/dist/engines/secrets.d.ts.map +1 -0
- package/dist/engines/secrets.js +260 -0
- package/dist/engines/secrets.js.map +1 -0
- package/dist/engines/semgrep.d.ts +3 -0
- package/dist/engines/semgrep.d.ts.map +1 -0
- package/dist/engines/semgrep.js +173 -0
- package/dist/engines/semgrep.js.map +1 -0
- package/dist/engines/types.d.ts +30 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +3 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/engines/url-scanner.d.ts +3 -0
- package/dist/engines/url-scanner.d.ts.map +1 -0
- package/dist/engines/url-scanner.js +469 -0
- package/dist/engines/url-scanner.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +32 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +237 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/rules/.gitkeep +0 -0
- package/dist/rules/ai-llm-security.yaml +199 -0
- package/dist/rules/api-security.yaml +489 -0
- package/dist/rules/auth-patterns.yaml +406 -0
- package/dist/rules/crypto-patterns.yaml +227 -0
- package/dist/rules/database-cloud-security.yaml +169 -0
- package/dist/rules/general-security.yaml +588 -0
- package/dist/rules/injection-patterns.yaml +318 -0
- package/dist/rules/nextjs-security.yaml +532 -0
- package/dist/rules/node-security.yaml +380 -0
- package/dist/rules/rules/.gitkeep +0 -0
- package/dist/rules/rules/ai-llm-security.yaml +199 -0
- package/dist/rules/rules/api-security.yaml +489 -0
- package/dist/rules/rules/auth-patterns.yaml +406 -0
- package/dist/rules/rules/crypto-patterns.yaml +227 -0
- package/dist/rules/rules/database-cloud-security.yaml +169 -0
- package/dist/rules/rules/general-security.yaml +588 -0
- package/dist/rules/rules/injection-patterns.yaml +318 -0
- package/dist/rules/rules/nextjs-security.yaml +532 -0
- package/dist/rules/rules/node-security.yaml +380 -0
- package/dist/rules/rules/supabase-security.yaml +387 -0
- package/dist/rules/supabase-security.yaml +387 -0
- package/dist/scanning/agents/csharp-agent.d.ts +12 -0
- package/dist/scanning/agents/csharp-agent.d.ts.map +1 -0
- package/dist/scanning/agents/csharp-agent.js +592 -0
- package/dist/scanning/agents/csharp-agent.js.map +1 -0
- package/dist/scanning/agents/go-agent.d.ts +14 -0
- package/dist/scanning/agents/go-agent.d.ts.map +1 -0
- package/dist/scanning/agents/go-agent.js +641 -0
- package/dist/scanning/agents/go-agent.js.map +1 -0
- package/dist/scanning/agents/java-agent.d.ts +8 -0
- package/dist/scanning/agents/java-agent.d.ts.map +1 -0
- package/dist/scanning/agents/java-agent.js +807 -0
- package/dist/scanning/agents/java-agent.js.map +1 -0
- package/dist/scanning/agents/javascript-agent.d.ts +8 -0
- package/dist/scanning/agents/javascript-agent.d.ts.map +1 -0
- package/dist/scanning/agents/javascript-agent.js +77 -0
- package/dist/scanning/agents/javascript-agent.js.map +1 -0
- package/dist/scanning/agents/mobile-agent.d.ts +8 -0
- package/dist/scanning/agents/mobile-agent.d.ts.map +1 -0
- package/dist/scanning/agents/mobile-agent.js +916 -0
- package/dist/scanning/agents/mobile-agent.js.map +1 -0
- package/dist/scanning/agents/php-agent.d.ts +8 -0
- package/dist/scanning/agents/php-agent.d.ts.map +1 -0
- package/dist/scanning/agents/php-agent.js +679 -0
- package/dist/scanning/agents/php-agent.js.map +1 -0
- package/dist/scanning/agents/python-agent.d.ts +8 -0
- package/dist/scanning/agents/python-agent.d.ts.map +1 -0
- package/dist/scanning/agents/python-agent.js +701 -0
- package/dist/scanning/agents/python-agent.js.map +1 -0
- package/dist/scanning/agents/supabase-agent.d.ts +8 -0
- package/dist/scanning/agents/supabase-agent.d.ts.map +1 -0
- package/dist/scanning/agents/supabase-agent.js +484 -0
- package/dist/scanning/agents/supabase-agent.js.map +1 -0
- package/dist/scanning/orchestrator.d.ts +29 -0
- package/dist/scanning/orchestrator.d.ts.map +1 -0
- package/dist/scanning/orchestrator.js +186 -0
- package/dist/scanning/orchestrator.js.map +1 -0
- package/dist/scanning/tech-detector.d.ts +12 -0
- package/dist/scanning/tech-detector.d.ts.map +1 -0
- package/dist/scanning/tech-detector.js +252 -0
- package/dist/scanning/tech-detector.js.map +1 -0
- package/dist/scanning/types.d.ts +87 -0
- package/dist/scanning/types.d.ts.map +1 -0
- package/dist/scanning/types.js +5 -0
- package/dist/scanning/types.js.map +1 -0
- package/dist/utils/child-process.d.ts +2 -0
- package/dist/utils/child-process.d.ts.map +1 -0
- package/dist/utils/child-process.js +4 -0
- package/dist/utils/child-process.js.map +1 -0
- package/dist/utils/context-classifier.d.ts +11 -0
- package/dist/utils/context-classifier.d.ts.map +1 -0
- package/dist/utils/context-classifier.js +79 -0
- package/dist/utils/context-classifier.js.map +1 -0
- package/dist/utils/exec.d.ts +18 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +51 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/file-filter.d.ts +4 -0
- package/dist/utils/file-filter.d.ts.map +1 -0
- package/dist/utils/file-filter.js +68 -0
- package/dist/utils/file-filter.js.map +1 -0
- package/dist/utils/fs.d.ts +2 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +5 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +27 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/post-processor.d.ts +10 -0
- package/dist/utils/post-processor.d.ts.map +1 -0
- package/dist/utils/post-processor.js +183 -0
- package/dist/utils/post-processor.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
# ID 77: Session Fixation - no session regeneration after login
|
|
3
|
+
- id: datahogo-session-fixation
|
|
4
|
+
patterns:
|
|
5
|
+
- pattern-either:
|
|
6
|
+
- pattern: |
|
|
7
|
+
async function login(...) {
|
|
8
|
+
...
|
|
9
|
+
}
|
|
10
|
+
- pattern: |
|
|
11
|
+
async function signin(...) {
|
|
12
|
+
...
|
|
13
|
+
}
|
|
14
|
+
- pattern-not: |
|
|
15
|
+
async function $FUNC(...) {
|
|
16
|
+
...
|
|
17
|
+
$SESSION.regenerate(...)
|
|
18
|
+
...
|
|
19
|
+
}
|
|
20
|
+
- pattern-not: |
|
|
21
|
+
async function $FUNC(...) {
|
|
22
|
+
...
|
|
23
|
+
regenerateSession(...)
|
|
24
|
+
...
|
|
25
|
+
}
|
|
26
|
+
message: "Login function should regenerate session ID to prevent session fixation attacks"
|
|
27
|
+
severity: ERROR
|
|
28
|
+
languages: [typescript, javascript]
|
|
29
|
+
metadata:
|
|
30
|
+
datahogo_id: 77
|
|
31
|
+
datahogo_category: "auth-sessions"
|
|
32
|
+
owasp_ref: "A07:2021"
|
|
33
|
+
|
|
34
|
+
# ID 79: Weak password policy - no length check
|
|
35
|
+
- id: datahogo-no-password-length-check
|
|
36
|
+
patterns:
|
|
37
|
+
- pattern-either:
|
|
38
|
+
- pattern: |
|
|
39
|
+
const password = $INPUT
|
|
40
|
+
...
|
|
41
|
+
$DB.$METHOD({ password: $HASH })
|
|
42
|
+
- pattern: |
|
|
43
|
+
function $FUNC($PASSWORD, ...) {
|
|
44
|
+
...
|
|
45
|
+
bcrypt.hash($PASSWORD, ...)
|
|
46
|
+
...
|
|
47
|
+
}
|
|
48
|
+
- pattern-not: |
|
|
49
|
+
$PASSWORD.length >= $NUM
|
|
50
|
+
- pattern-not: |
|
|
51
|
+
$PASSWORD.length > $NUM
|
|
52
|
+
- pattern-not: |
|
|
53
|
+
if ($PASSWORD.length $OP $NUM)
|
|
54
|
+
message: "Password validation missing length requirement (minimum 8-12 characters recommended)"
|
|
55
|
+
severity: WARNING
|
|
56
|
+
languages: [typescript, javascript]
|
|
57
|
+
metadata:
|
|
58
|
+
datahogo_id: 79
|
|
59
|
+
datahogo_category: "auth-sessions"
|
|
60
|
+
owasp_ref: "A07:2021"
|
|
61
|
+
|
|
62
|
+
# ID 80: OAuth state missing
|
|
63
|
+
- id: datahogo-oauth-missing-state
|
|
64
|
+
patterns:
|
|
65
|
+
- pattern-either:
|
|
66
|
+
- pattern: |
|
|
67
|
+
const authUrl = `$OAUTH_ENDPOINT?client_id=$CLIENT_ID&redirect_uri=$REDIRECT`
|
|
68
|
+
- pattern: |
|
|
69
|
+
new URL($OAUTH_URL)
|
|
70
|
+
...
|
|
71
|
+
$URL.searchParams.append('client_id', ...)
|
|
72
|
+
$URL.searchParams.append('redirect_uri', ...)
|
|
73
|
+
- pattern-not: |
|
|
74
|
+
$URL.searchParams.append('state', ...)
|
|
75
|
+
- pattern-not: |
|
|
76
|
+
state=$STATE
|
|
77
|
+
message: "OAuth redirect missing state parameter - vulnerable to CSRF attacks"
|
|
78
|
+
severity: ERROR
|
|
79
|
+
languages: [typescript, javascript]
|
|
80
|
+
metadata:
|
|
81
|
+
datahogo_id: 80
|
|
82
|
+
datahogo_category: "auth-sessions"
|
|
83
|
+
owasp_ref: "A07:2021"
|
|
84
|
+
|
|
85
|
+
# ID 81: Token not invalidated on logout
|
|
86
|
+
- id: datahogo-logout-no-invalidation
|
|
87
|
+
patterns:
|
|
88
|
+
- pattern-either:
|
|
89
|
+
- pattern: |
|
|
90
|
+
async function logout(...) {
|
|
91
|
+
...
|
|
92
|
+
$RESPONSE.redirect(...)
|
|
93
|
+
}
|
|
94
|
+
- pattern: |
|
|
95
|
+
async function signout(...) {
|
|
96
|
+
...
|
|
97
|
+
}
|
|
98
|
+
- pattern-not: |
|
|
99
|
+
async function $FUNC(...) {
|
|
100
|
+
...
|
|
101
|
+
$DB.$METHOD({ token: ... })
|
|
102
|
+
...
|
|
103
|
+
}
|
|
104
|
+
- pattern-not: |
|
|
105
|
+
async function $FUNC(...) {
|
|
106
|
+
...
|
|
107
|
+
$SESSION.destroy(...)
|
|
108
|
+
...
|
|
109
|
+
}
|
|
110
|
+
- pattern-not: |
|
|
111
|
+
async function $FUNC(...) {
|
|
112
|
+
...
|
|
113
|
+
blacklist.add(...)
|
|
114
|
+
...
|
|
115
|
+
}
|
|
116
|
+
message: "Logout function should invalidate tokens or destroy sessions"
|
|
117
|
+
severity: WARNING
|
|
118
|
+
languages: [typescript, javascript]
|
|
119
|
+
metadata:
|
|
120
|
+
datahogo_id: 81
|
|
121
|
+
datahogo_category: "auth-sessions"
|
|
122
|
+
owasp_ref: "A07:2021"
|
|
123
|
+
|
|
124
|
+
# ID 82: No session invalidation on password change
|
|
125
|
+
- id: datahogo-password-change-no-session-invalidation
|
|
126
|
+
patterns:
|
|
127
|
+
- pattern-either:
|
|
128
|
+
- pattern: |
|
|
129
|
+
async function changePassword(...) {
|
|
130
|
+
...
|
|
131
|
+
$DB.update({ password: ... })
|
|
132
|
+
...
|
|
133
|
+
}
|
|
134
|
+
- pattern: |
|
|
135
|
+
async function updatePassword(...) {
|
|
136
|
+
...
|
|
137
|
+
}
|
|
138
|
+
- pattern-not: |
|
|
139
|
+
async function $FUNC(...) {
|
|
140
|
+
...
|
|
141
|
+
$SESSION.destroy(...)
|
|
142
|
+
...
|
|
143
|
+
}
|
|
144
|
+
- pattern-not: |
|
|
145
|
+
async function $FUNC(...) {
|
|
146
|
+
...
|
|
147
|
+
invalidateAllSessions(...)
|
|
148
|
+
...
|
|
149
|
+
}
|
|
150
|
+
message: "Password change should invalidate all active sessions for security"
|
|
151
|
+
severity: WARNING
|
|
152
|
+
languages: [typescript, javascript]
|
|
153
|
+
metadata:
|
|
154
|
+
datahogo_id: 82
|
|
155
|
+
datahogo_category: "auth-sessions"
|
|
156
|
+
owasp_ref: "A07:2021"
|
|
157
|
+
|
|
158
|
+
# ID 84: Insecure password reset - no TTL
|
|
159
|
+
- id: datahogo-password-reset-no-expiry
|
|
160
|
+
patterns:
|
|
161
|
+
- pattern-either:
|
|
162
|
+
- pattern: |
|
|
163
|
+
const resetToken = $RANDOM
|
|
164
|
+
...
|
|
165
|
+
$DB.save({ resetToken: $TOKEN })
|
|
166
|
+
- pattern: |
|
|
167
|
+
function createPasswordResetToken(...) {
|
|
168
|
+
...
|
|
169
|
+
return $TOKEN
|
|
170
|
+
}
|
|
171
|
+
- pattern-not: |
|
|
172
|
+
expiresAt: ...
|
|
173
|
+
- pattern-not: |
|
|
174
|
+
expires_at: ...
|
|
175
|
+
- pattern-not: |
|
|
176
|
+
expiry: ...
|
|
177
|
+
- pattern-not: |
|
|
178
|
+
ttl: ...
|
|
179
|
+
message: "Password reset token should have an expiration time (15-60 minutes recommended)"
|
|
180
|
+
severity: ERROR
|
|
181
|
+
languages: [typescript, javascript]
|
|
182
|
+
metadata:
|
|
183
|
+
datahogo_id: 84
|
|
184
|
+
datahogo_category: "auth-sessions"
|
|
185
|
+
owasp_ref: "A07:2021"
|
|
186
|
+
|
|
187
|
+
# ID 85: User enumeration - different error messages
|
|
188
|
+
- id: datahogo-user-enumeration
|
|
189
|
+
patterns:
|
|
190
|
+
- pattern-either:
|
|
191
|
+
- pattern: |
|
|
192
|
+
if (!$USER) {
|
|
193
|
+
throw new Error("User not found")
|
|
194
|
+
}
|
|
195
|
+
- pattern: |
|
|
196
|
+
if (!$USER) {
|
|
197
|
+
return { error: "User does not exist" }
|
|
198
|
+
}
|
|
199
|
+
- pattern: |
|
|
200
|
+
if (!$USER) {
|
|
201
|
+
$RESPONSE.status(404).json({ error: "User not found" })
|
|
202
|
+
}
|
|
203
|
+
message: "Login error messages should be generic to prevent user enumeration (use 'Invalid credentials')"
|
|
204
|
+
severity: INFO
|
|
205
|
+
languages: [typescript, javascript]
|
|
206
|
+
metadata:
|
|
207
|
+
datahogo_id: 85
|
|
208
|
+
datahogo_category: "auth-sessions"
|
|
209
|
+
owasp_ref: "A07:2021"
|
|
210
|
+
|
|
211
|
+
# ID 156: No password policy enforcement
|
|
212
|
+
- id: datahogo-no-password-policy
|
|
213
|
+
patterns:
|
|
214
|
+
- pattern-either:
|
|
215
|
+
- pattern: |
|
|
216
|
+
async function register(..., password: $TYPE, ...) {
|
|
217
|
+
...
|
|
218
|
+
bcrypt.hash(password, ...)
|
|
219
|
+
...
|
|
220
|
+
}
|
|
221
|
+
- pattern: |
|
|
222
|
+
async function signup(...) {
|
|
223
|
+
...
|
|
224
|
+
const hashedPassword = await $HASH(password, ...)
|
|
225
|
+
...
|
|
226
|
+
}
|
|
227
|
+
- pattern-not: |
|
|
228
|
+
if (password.length $OP $NUM && $REGEX.test(password))
|
|
229
|
+
- pattern-not: |
|
|
230
|
+
validatePassword(password)
|
|
231
|
+
- pattern-not: |
|
|
232
|
+
passwordSchema.parse(...)
|
|
233
|
+
message: "Password registration missing policy enforcement (length, complexity, common passwords)"
|
|
234
|
+
severity: WARNING
|
|
235
|
+
languages: [typescript, javascript]
|
|
236
|
+
metadata:
|
|
237
|
+
datahogo_id: 156
|
|
238
|
+
datahogo_category: "best-practices"
|
|
239
|
+
owasp_ref: "A07:2021"
|
|
240
|
+
|
|
241
|
+
# ID 159: No email verification
|
|
242
|
+
- id: datahogo-no-email-verification
|
|
243
|
+
patterns:
|
|
244
|
+
- pattern: |
|
|
245
|
+
async function register(...) {
|
|
246
|
+
...
|
|
247
|
+
$DB.create({ email: $EMAIL, ... })
|
|
248
|
+
...
|
|
249
|
+
}
|
|
250
|
+
- pattern-not: |
|
|
251
|
+
async function register(...) {
|
|
252
|
+
...
|
|
253
|
+
sendVerificationEmail(...)
|
|
254
|
+
...
|
|
255
|
+
}
|
|
256
|
+
- pattern-not: |
|
|
257
|
+
async function register(...) {
|
|
258
|
+
...
|
|
259
|
+
emailVerified: false
|
|
260
|
+
...
|
|
261
|
+
}
|
|
262
|
+
message: "User registration should require email verification to prevent fake accounts"
|
|
263
|
+
severity: WARNING
|
|
264
|
+
languages: [typescript, javascript]
|
|
265
|
+
metadata:
|
|
266
|
+
datahogo_id: 159
|
|
267
|
+
datahogo_category: "best-practices"
|
|
268
|
+
owasp_ref: "A07:2021"
|
|
269
|
+
|
|
270
|
+
# ID 164: No confirmation for critical actions
|
|
271
|
+
- id: datahogo-no-delete-confirmation
|
|
272
|
+
patterns:
|
|
273
|
+
- pattern-either:
|
|
274
|
+
- pattern: |
|
|
275
|
+
async function deleteAccount(...) {
|
|
276
|
+
...
|
|
277
|
+
$DB.delete(...)
|
|
278
|
+
}
|
|
279
|
+
- pattern: |
|
|
280
|
+
async function DELETE(...) {
|
|
281
|
+
...
|
|
282
|
+
$DB.users.delete(...)
|
|
283
|
+
...
|
|
284
|
+
}
|
|
285
|
+
- pattern-not: |
|
|
286
|
+
if ($CONFIRM === $PASSWORD)
|
|
287
|
+
- pattern-not: |
|
|
288
|
+
if (confirmed)
|
|
289
|
+
- pattern-not: |
|
|
290
|
+
requirePasswordConfirmation(...)
|
|
291
|
+
message: "Critical actions like account deletion should require password confirmation"
|
|
292
|
+
severity: WARNING
|
|
293
|
+
languages: [typescript, javascript]
|
|
294
|
+
metadata:
|
|
295
|
+
datahogo_id: 164
|
|
296
|
+
datahogo_category: "best-practices"
|
|
297
|
+
owasp_ref: "A07:2021"
|
|
298
|
+
|
|
299
|
+
# ID 77 Extended: Session token reuse after privilege escalation
|
|
300
|
+
- id: datahogo-session-reuse-privilege-change
|
|
301
|
+
patterns:
|
|
302
|
+
- pattern: |
|
|
303
|
+
async function $FUNC(...) {
|
|
304
|
+
...
|
|
305
|
+
$DB.update({ role: $NEW_ROLE })
|
|
306
|
+
...
|
|
307
|
+
}
|
|
308
|
+
- pattern-not: |
|
|
309
|
+
async function $FUNC(...) {
|
|
310
|
+
...
|
|
311
|
+
$SESSION.regenerate(...)
|
|
312
|
+
...
|
|
313
|
+
}
|
|
314
|
+
message: "Session should be regenerated after privilege changes to prevent session adoption attacks"
|
|
315
|
+
severity: WARNING
|
|
316
|
+
languages: [typescript, javascript]
|
|
317
|
+
metadata:
|
|
318
|
+
datahogo_id: 77
|
|
319
|
+
datahogo_category: "auth-sessions"
|
|
320
|
+
owasp_ref: "A07:2021"
|
|
321
|
+
|
|
322
|
+
# ID 80 Extended: OAuth redirect_uri not validated
|
|
323
|
+
- id: datahogo-oauth-open-redirect
|
|
324
|
+
patterns:
|
|
325
|
+
- pattern-either:
|
|
326
|
+
- pattern: |
|
|
327
|
+
const redirect_uri = $REQ.query.redirect_uri
|
|
328
|
+
...
|
|
329
|
+
$OAUTH.$METHOD({ redirect_uri })
|
|
330
|
+
- pattern: |
|
|
331
|
+
const callbackUrl = $REQ.body.callback
|
|
332
|
+
...
|
|
333
|
+
redirect(callbackUrl)
|
|
334
|
+
- pattern-not: |
|
|
335
|
+
if (allowedUrls.includes($URL))
|
|
336
|
+
- pattern-not: |
|
|
337
|
+
if ($URL.startsWith($DOMAIN))
|
|
338
|
+
message: "OAuth redirect_uri should be validated against allowlist to prevent open redirects"
|
|
339
|
+
severity: ERROR
|
|
340
|
+
languages: [typescript, javascript]
|
|
341
|
+
metadata:
|
|
342
|
+
datahogo_id: 80
|
|
343
|
+
datahogo_category: "auth-sessions"
|
|
344
|
+
owasp_ref: "A07:2021"
|
|
345
|
+
|
|
346
|
+
# JWT without expiration
|
|
347
|
+
- id: datahogo-jwt-no-expiration
|
|
348
|
+
patterns:
|
|
349
|
+
- pattern-either:
|
|
350
|
+
- pattern: |
|
|
351
|
+
jwt.sign($PAYLOAD, $SECRET)
|
|
352
|
+
- pattern: |
|
|
353
|
+
jwt.sign($PAYLOAD, $SECRET, { algorithm: $ALG })
|
|
354
|
+
- pattern-not: |
|
|
355
|
+
jwt.sign($PAYLOAD, $SECRET, { ..., expiresIn: ... })
|
|
356
|
+
- pattern-not: |
|
|
357
|
+
jwt.sign($PAYLOAD, $SECRET, { ..., exp: ... })
|
|
358
|
+
message: "JWT tokens should have an expiration time (expiresIn or exp claim)"
|
|
359
|
+
severity: ERROR
|
|
360
|
+
languages: [typescript, javascript]
|
|
361
|
+
metadata:
|
|
362
|
+
datahogo_id: 56
|
|
363
|
+
datahogo_category: "vibecoding"
|
|
364
|
+
owasp_ref: "A07:2021"
|
|
365
|
+
|
|
366
|
+
# Tokens in localStorage
|
|
367
|
+
- id: datahogo-token-in-localstorage
|
|
368
|
+
patterns:
|
|
369
|
+
- pattern-either:
|
|
370
|
+
- pattern: localStorage.setItem($KEY, $TOKEN)
|
|
371
|
+
- pattern: sessionStorage.setItem($KEY, $TOKEN)
|
|
372
|
+
- metavariable-regex:
|
|
373
|
+
metavariable: $KEY
|
|
374
|
+
regex: .*(token|jwt|auth|session|access|refresh).*
|
|
375
|
+
message: "Authentication tokens in localStorage/sessionStorage are vulnerable to XSS. Use httpOnly cookies"
|
|
376
|
+
severity: ERROR
|
|
377
|
+
languages: [typescript, javascript]
|
|
378
|
+
metadata:
|
|
379
|
+
datahogo_id: 47
|
|
380
|
+
datahogo_category: "react-nextjs"
|
|
381
|
+
owasp_ref: "A07:2021"
|
|
382
|
+
|
|
383
|
+
# ID 156 Extended: Common passwords not checked
|
|
384
|
+
- id: datahogo-no-common-password-check
|
|
385
|
+
patterns:
|
|
386
|
+
- pattern: |
|
|
387
|
+
async function $FUNC(..., password: string, ...) {
|
|
388
|
+
...
|
|
389
|
+
if (password.length >= $NUM) {
|
|
390
|
+
...
|
|
391
|
+
}
|
|
392
|
+
...
|
|
393
|
+
}
|
|
394
|
+
- pattern-not: |
|
|
395
|
+
commonPasswords.includes(password)
|
|
396
|
+
- pattern-not: |
|
|
397
|
+
isCommonPassword(password)
|
|
398
|
+
- pattern-not: |
|
|
399
|
+
hibp.check(password)
|
|
400
|
+
message: "Password validation should check against common/breached passwords list"
|
|
401
|
+
severity: INFO
|
|
402
|
+
languages: [typescript, javascript]
|
|
403
|
+
metadata:
|
|
404
|
+
datahogo_id: 156
|
|
405
|
+
datahogo_category: "best-practices"
|
|
406
|
+
owasp_ref: "A07:2021"
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
# ID 121: ECB mode in cipher
|
|
3
|
+
- id: datahogo-ecb-mode-cipher
|
|
4
|
+
patterns:
|
|
5
|
+
- pattern-either:
|
|
6
|
+
- pattern: crypto.createCipheriv("aes-$BITS-ecb", ...)
|
|
7
|
+
- pattern: crypto.createDecipheriv("aes-$BITS-ecb", ...)
|
|
8
|
+
- pattern: crypto.createCipheriv('aes-$BITS-ecb', ...)
|
|
9
|
+
- pattern: crypto.createDecipheriv('aes-$BITS-ecb', ...)
|
|
10
|
+
message: "ECB cipher mode does not use an IV and reveals patterns in plaintext - use CBC or GCM mode instead"
|
|
11
|
+
severity: WARNING
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
metadata:
|
|
14
|
+
datahogo_id: 121
|
|
15
|
+
datahogo_category: "cryptography"
|
|
16
|
+
owasp_ref: "A02:2021"
|
|
17
|
+
|
|
18
|
+
# ID 122: Static IV / Nonce
|
|
19
|
+
- id: datahogo-static-iv-buffer
|
|
20
|
+
patterns:
|
|
21
|
+
- pattern-either:
|
|
22
|
+
- pattern: |
|
|
23
|
+
const iv = Buffer.alloc($SIZE, 0)
|
|
24
|
+
- pattern: |
|
|
25
|
+
const iv = Buffer.alloc($SIZE)
|
|
26
|
+
- pattern: |
|
|
27
|
+
const nonce = Buffer.alloc($SIZE, 0)
|
|
28
|
+
- pattern: |
|
|
29
|
+
const iv = Buffer.from("$STATIC_STRING")
|
|
30
|
+
message: "Static or zero-filled IV/nonce makes encryption deterministic - use crypto.randomBytes() for each encryption"
|
|
31
|
+
severity: ERROR
|
|
32
|
+
languages: [typescript, javascript]
|
|
33
|
+
metadata:
|
|
34
|
+
datahogo_id: 122
|
|
35
|
+
datahogo_category: "cryptography"
|
|
36
|
+
owasp_ref: "A02:2021"
|
|
37
|
+
|
|
38
|
+
- id: datahogo-static-iv-hardcoded
|
|
39
|
+
patterns:
|
|
40
|
+
- pattern-either:
|
|
41
|
+
- pattern: |
|
|
42
|
+
const $IV = "$STRING"
|
|
43
|
+
...
|
|
44
|
+
crypto.createCipheriv($ALGO, $KEY, $IV)
|
|
45
|
+
- pattern: |
|
|
46
|
+
const $IV = '$STRING'
|
|
47
|
+
...
|
|
48
|
+
crypto.createCipheriv($ALGO, $KEY, $IV)
|
|
49
|
+
message: "Hardcoded IV/nonce in cipher - generate a unique random IV for every encryption operation"
|
|
50
|
+
severity: ERROR
|
|
51
|
+
languages: [typescript, javascript]
|
|
52
|
+
metadata:
|
|
53
|
+
datahogo_id: 122
|
|
54
|
+
datahogo_category: "cryptography"
|
|
55
|
+
owasp_ref: "A02:2021"
|
|
56
|
+
|
|
57
|
+
# ID 123: Weak key size
|
|
58
|
+
- id: datahogo-weak-rsa-key-size
|
|
59
|
+
patterns:
|
|
60
|
+
- pattern-either:
|
|
61
|
+
- pattern: |
|
|
62
|
+
crypto.generateKeyPair("rsa", { modulusLength: $SIZE, ... }, ...)
|
|
63
|
+
- pattern: |
|
|
64
|
+
crypto.generateKeyPairSync("rsa", { modulusLength: $SIZE, ... })
|
|
65
|
+
- metavariable-regex:
|
|
66
|
+
metavariable: $SIZE
|
|
67
|
+
regex: ^(512|1024)$
|
|
68
|
+
message: "RSA key size below 2048 bits is cryptographically weak - use at least 2048 bits (4096 recommended)"
|
|
69
|
+
severity: WARNING
|
|
70
|
+
languages: [typescript, javascript]
|
|
71
|
+
metadata:
|
|
72
|
+
datahogo_id: 123
|
|
73
|
+
datahogo_category: "cryptography"
|
|
74
|
+
owasp_ref: "A02:2021"
|
|
75
|
+
|
|
76
|
+
- id: datahogo-weak-aes-key-size
|
|
77
|
+
patterns:
|
|
78
|
+
- pattern-either:
|
|
79
|
+
- pattern: crypto.createCipheriv("aes-64-$MODE", ...)
|
|
80
|
+
- pattern: crypto.createCipheriv('aes-64-$MODE', ...)
|
|
81
|
+
message: "AES key size below 128 bits is insufficient - use AES-128, AES-192, or AES-256"
|
|
82
|
+
severity: WARNING
|
|
83
|
+
languages: [typescript, javascript]
|
|
84
|
+
metadata:
|
|
85
|
+
datahogo_id: 123
|
|
86
|
+
datahogo_category: "cryptography"
|
|
87
|
+
owasp_ref: "A02:2021"
|
|
88
|
+
|
|
89
|
+
# ID 124: Certificate validation disabled
|
|
90
|
+
- id: datahogo-tls-reject-unauthorized-env
|
|
91
|
+
patterns:
|
|
92
|
+
- pattern-either:
|
|
93
|
+
- pattern: process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
|
94
|
+
- pattern: process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
|
95
|
+
- pattern: process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0"
|
|
96
|
+
message: "Disabling TLS certificate validation exposes all HTTPS connections to man-in-the-middle attacks"
|
|
97
|
+
severity: CRITICAL
|
|
98
|
+
languages: [typescript, javascript]
|
|
99
|
+
metadata:
|
|
100
|
+
datahogo_id: 124
|
|
101
|
+
datahogo_category: "cryptography"
|
|
102
|
+
owasp_ref: "A02:2021"
|
|
103
|
+
|
|
104
|
+
- id: datahogo-tls-reject-unauthorized-agent
|
|
105
|
+
patterns:
|
|
106
|
+
- pattern-either:
|
|
107
|
+
- pattern: |
|
|
108
|
+
new https.Agent({ rejectUnauthorized: false })
|
|
109
|
+
- pattern: |
|
|
110
|
+
https.request({ ..., rejectUnauthorized: false, ... })
|
|
111
|
+
- pattern: |
|
|
112
|
+
axios.create({ ..., httpsAgent: new https.Agent({ rejectUnauthorized: false }) })
|
|
113
|
+
message: "TLS certificate validation disabled in HTTPS agent - remove rejectUnauthorized: false before deploying to production"
|
|
114
|
+
severity: CRITICAL
|
|
115
|
+
languages: [typescript, javascript]
|
|
116
|
+
metadata:
|
|
117
|
+
datahogo_id: 124
|
|
118
|
+
datahogo_category: "cryptography"
|
|
119
|
+
owasp_ref: "A02:2021"
|
|
120
|
+
|
|
121
|
+
# ID 125: Weak PRNG for security tokens
|
|
122
|
+
- id: datahogo-math-random-token
|
|
123
|
+
patterns:
|
|
124
|
+
- pattern-either:
|
|
125
|
+
- pattern: |
|
|
126
|
+
const $TOKEN = Math.random()
|
|
127
|
+
- pattern: |
|
|
128
|
+
const $ID = Math.random().toString(...)
|
|
129
|
+
- pattern: |
|
|
130
|
+
token = Math.random().toString($BASE).slice($N)
|
|
131
|
+
- pattern: |
|
|
132
|
+
id = Math.random().toString($BASE).substr($N)
|
|
133
|
+
message: "Math.random() is not cryptographically secure - use crypto.randomBytes() or crypto.randomUUID() for tokens and IDs"
|
|
134
|
+
severity: ERROR
|
|
135
|
+
languages: [typescript, javascript]
|
|
136
|
+
metadata:
|
|
137
|
+
datahogo_id: 125
|
|
138
|
+
datahogo_category: "cryptography"
|
|
139
|
+
owasp_ref: "A02:2021"
|
|
140
|
+
|
|
141
|
+
- id: datahogo-date-now-token
|
|
142
|
+
patterns:
|
|
143
|
+
- pattern-either:
|
|
144
|
+
- pattern: |
|
|
145
|
+
const $TOKEN = Date.now().toString()
|
|
146
|
+
- pattern: |
|
|
147
|
+
const $TOKEN = String(Date.now())
|
|
148
|
+
- pattern: |
|
|
149
|
+
token: Date.now()
|
|
150
|
+
- metavariable-regex:
|
|
151
|
+
metavariable: $TOKEN
|
|
152
|
+
regex: .*(token|secret|key|reset|nonce|csrf|session).*
|
|
153
|
+
message: "Date.now() is predictable and should not be used for security tokens - use crypto.randomBytes()"
|
|
154
|
+
severity: ERROR
|
|
155
|
+
languages: [typescript, javascript]
|
|
156
|
+
metadata:
|
|
157
|
+
datahogo_id: 125
|
|
158
|
+
datahogo_category: "cryptography"
|
|
159
|
+
owasp_ref: "A02:2021"
|
|
160
|
+
|
|
161
|
+
# ID 126: JWT algorithm none
|
|
162
|
+
- id: datahogo-jwt-algorithm-none
|
|
163
|
+
patterns:
|
|
164
|
+
- pattern-either:
|
|
165
|
+
- pattern: jwt.verify($TOKEN, $SECRET, { algorithms: [..., "none", ...] })
|
|
166
|
+
- pattern: jwt.verify($TOKEN, $SECRET, { algorithms: ["none"] })
|
|
167
|
+
- pattern: jwt.sign($PAYLOAD, $SECRET, { algorithm: "none" })
|
|
168
|
+
- pattern: jwt.sign($PAYLOAD, "", ...)
|
|
169
|
+
message: "JWT 'none' algorithm allows forged tokens with no signature verification - always use a strong algorithm (RS256, ES256)"
|
|
170
|
+
severity: CRITICAL
|
|
171
|
+
languages: [typescript, javascript]
|
|
172
|
+
metadata:
|
|
173
|
+
datahogo_id: 126
|
|
174
|
+
datahogo_category: "cryptography"
|
|
175
|
+
owasp_ref: "A02:2021"
|
|
176
|
+
|
|
177
|
+
- id: datahogo-jwt-empty-secret
|
|
178
|
+
patterns:
|
|
179
|
+
- pattern-either:
|
|
180
|
+
- pattern: jwt.verify($TOKEN, "")
|
|
181
|
+
- pattern: jwt.verify($TOKEN, '')
|
|
182
|
+
- pattern: jwt.verify($TOKEN, null)
|
|
183
|
+
- pattern: jwt.verify($TOKEN, undefined)
|
|
184
|
+
message: "JWT verification with empty or null secret disables signature validation - always use a strong secret"
|
|
185
|
+
severity: CRITICAL
|
|
186
|
+
languages: [typescript, javascript]
|
|
187
|
+
metadata:
|
|
188
|
+
datahogo_id: 126
|
|
189
|
+
datahogo_category: "cryptography"
|
|
190
|
+
owasp_ref: "A02:2021"
|
|
191
|
+
|
|
192
|
+
# ID 127: Hardcoded encryption key
|
|
193
|
+
- id: datahogo-hardcoded-encryption-key-string
|
|
194
|
+
patterns:
|
|
195
|
+
- pattern-either:
|
|
196
|
+
- pattern: |
|
|
197
|
+
const $KEY = "$LITERAL_KEY"
|
|
198
|
+
...
|
|
199
|
+
crypto.createCipheriv($ALGO, $KEY, ...)
|
|
200
|
+
- pattern: |
|
|
201
|
+
const $KEY = '$LITERAL_KEY'
|
|
202
|
+
...
|
|
203
|
+
crypto.createCipheriv($ALGO, $KEY, ...)
|
|
204
|
+
- pattern: |
|
|
205
|
+
crypto.createCipheriv($ALGO, "$LITERAL_KEY", ...)
|
|
206
|
+
- pattern: |
|
|
207
|
+
crypto.createCipheriv($ALGO, '$LITERAL_KEY', ...)
|
|
208
|
+
message: "Hardcoded encryption key in source code - load from environment variables or secrets manager"
|
|
209
|
+
severity: ERROR
|
|
210
|
+
languages: [typescript, javascript]
|
|
211
|
+
metadata:
|
|
212
|
+
datahogo_id: 127
|
|
213
|
+
datahogo_category: "cryptography"
|
|
214
|
+
owasp_ref: "A02:2021"
|
|
215
|
+
|
|
216
|
+
- id: datahogo-hardcoded-hmac-key
|
|
217
|
+
patterns:
|
|
218
|
+
- pattern-either:
|
|
219
|
+
- pattern: crypto.createHmac($ALGO, "$LITERAL_KEY")
|
|
220
|
+
- pattern: crypto.createHmac($ALGO, '$LITERAL_KEY')
|
|
221
|
+
message: "Hardcoded HMAC key in source code - load secret from environment variables"
|
|
222
|
+
severity: ERROR
|
|
223
|
+
languages: [typescript, javascript]
|
|
224
|
+
metadata:
|
|
225
|
+
datahogo_id: 127
|
|
226
|
+
datahogo_category: "cryptography"
|
|
227
|
+
owasp_ref: "A02:2021"
|