oauthlint-rules 0.3.0 → 0.4.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/dist/loader.d.ts +1 -1
- package/dist/schema.d.ts +79 -19
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +13 -4
- package/dist/schema.js.map +1 -1
- package/package.json +1 -1
- package/rules/cookie/no-samesite.yml +1 -1
- package/rules/cookie/samesite-none-insecure.yml +23 -1
- package/rules/cors/null-origin.yml +1 -1
- package/rules/cors/reflect-origin.yml +1 -1
- package/rules/flow/basic-auth-in-log.yml +99 -0
- package/rules/flow/open-redirect.yml +53 -21
- package/rules/flow/ssrf.yml +61 -21
- package/rules/flow/timing-unsafe-compare.yml +19 -0
- package/rules/go/cookie/insecure.yml +1 -1
- package/rules/go/cors/allow-all.yml +1 -1
- package/rules/go/flow/open-redirect.yml +16 -6
- package/rules/go/flow/ssrf.yml +16 -7
- package/rules/go/oauth/ropc-grant.yml +15 -0
- package/rules/java/cookie/insecure.yml +1 -1
- package/rules/java/cors/allow-all.yml +1 -1
- package/rules/java/cors/credentialed-wildcard.yml +1 -1
- package/rules/java/flow/ssrf.yml +113 -0
- package/rules/java/session/fixation-disabled.yml +1 -1
- package/rules/java/tls/trust-all-certs.yml +18 -7
- package/rules/oauth/no-state.yml +9 -8
- package/rules/oauth/open-redirect-callback.yml +18 -3
- package/rules/oauth/ropc-grant.yml +8 -3
- package/rules/oauth/static-state.yml +8 -7
- package/rules/py/cookie/insecure-flags.yml +1 -1
- package/rules/py/cors/allow-all.yml +1 -1
- package/rules/py/flow/requests-verify-disabled.yml +1 -1
- package/rules/py/oauth/ropc-grant.yml +12 -4
- package/rules/rust/cookie/insecure.yml +1 -1
- package/rules/rust/cors/permissive.yml +1 -1
- package/rules/rust/flow/ssrf.yml +90 -0
- package/rules/rust/oauth/ropc-grant.yml +17 -0
- package/rules/rust/oauth/static-state.yml +25 -5
- package/rules/tls/reject-unauthorized.yml +1 -1
package/dist/loader.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare function buildManifest(root?: string): Promise<{
|
|
|
26
26
|
oauthlintId: string;
|
|
27
27
|
docUrl: string;
|
|
28
28
|
llmPrevalence: "HIGH" | "MEDIUM" | "LOW";
|
|
29
|
-
cwe: string
|
|
29
|
+
cwe: string;
|
|
30
30
|
owasp: string | undefined;
|
|
31
31
|
description: string;
|
|
32
32
|
sourceFile: string;
|
package/dist/schema.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const OAuthLintMetadataSchema: z.ZodObject<{
|
|
|
15
15
|
'oauthlint-rule-id': z.ZodString;
|
|
16
16
|
'oauthlint-doc-url': z.ZodString;
|
|
17
17
|
category: z.ZodLiteral<"security">;
|
|
18
|
-
cwe: z.
|
|
18
|
+
cwe: z.ZodString;
|
|
19
19
|
owasp: z.ZodOptional<z.ZodString>;
|
|
20
20
|
'llm-prevalence': z.ZodEnum<["HIGH", "MEDIUM", "LOW"]>;
|
|
21
21
|
references: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -24,8 +24,8 @@ export declare const OAuthLintMetadataSchema: z.ZodObject<{
|
|
|
24
24
|
'oauthlint-rule-id': string;
|
|
25
25
|
'oauthlint-doc-url': string;
|
|
26
26
|
category: "security";
|
|
27
|
+
cwe: string;
|
|
27
28
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
28
|
-
cwe?: string | undefined;
|
|
29
29
|
owasp?: string | undefined;
|
|
30
30
|
references?: string[] | undefined;
|
|
31
31
|
technology?: string[] | undefined;
|
|
@@ -33,8 +33,8 @@ export declare const OAuthLintMetadataSchema: z.ZodObject<{
|
|
|
33
33
|
'oauthlint-rule-id': string;
|
|
34
34
|
'oauthlint-doc-url': string;
|
|
35
35
|
category: "security";
|
|
36
|
+
cwe: string;
|
|
36
37
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
37
|
-
cwe?: string | undefined;
|
|
38
38
|
owasp?: string | undefined;
|
|
39
39
|
references?: string[] | undefined;
|
|
40
40
|
technology?: string[] | undefined;
|
|
@@ -49,7 +49,7 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
49
49
|
'oauthlint-rule-id': z.ZodString;
|
|
50
50
|
'oauthlint-doc-url': z.ZodString;
|
|
51
51
|
category: z.ZodLiteral<"security">;
|
|
52
|
-
cwe: z.
|
|
52
|
+
cwe: z.ZodString;
|
|
53
53
|
owasp: z.ZodOptional<z.ZodString>;
|
|
54
54
|
'llm-prevalence': z.ZodEnum<["HIGH", "MEDIUM", "LOW"]>;
|
|
55
55
|
references: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -58,8 +58,8 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
58
58
|
'oauthlint-rule-id': string;
|
|
59
59
|
'oauthlint-doc-url': string;
|
|
60
60
|
category: "security";
|
|
61
|
+
cwe: string;
|
|
61
62
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
62
|
-
cwe?: string | undefined;
|
|
63
63
|
owasp?: string | undefined;
|
|
64
64
|
references?: string[] | undefined;
|
|
65
65
|
technology?: string[] | undefined;
|
|
@@ -67,8 +67,8 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
67
67
|
'oauthlint-rule-id': string;
|
|
68
68
|
'oauthlint-doc-url': string;
|
|
69
69
|
category: "security";
|
|
70
|
+
cwe: string;
|
|
70
71
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
71
|
-
cwe?: string | undefined;
|
|
72
72
|
owasp?: string | undefined;
|
|
73
73
|
references?: string[] | undefined;
|
|
74
74
|
technology?: string[] | undefined;
|
|
@@ -81,6 +81,16 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
81
81
|
'pattern-either-regex': z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
82
82
|
patterns: z.ZodOptional<z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">>;
|
|
83
83
|
fix: z.ZodOptional<z.ZodString>;
|
|
84
|
+
paths: z.ZodOptional<z.ZodObject<{
|
|
85
|
+
include: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
86
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
87
|
+
}, "strip", z.ZodTypeAny, {
|
|
88
|
+
include?: string[] | undefined;
|
|
89
|
+
exclude?: string[] | undefined;
|
|
90
|
+
}, {
|
|
91
|
+
include?: string[] | undefined;
|
|
92
|
+
exclude?: string[] | undefined;
|
|
93
|
+
}>>;
|
|
84
94
|
mode: z.ZodOptional<z.ZodEnum<["search", "taint"]>>;
|
|
85
95
|
'pattern-sources': z.ZodOptional<z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">>;
|
|
86
96
|
'pattern-sinks': z.ZodOptional<z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">>;
|
|
@@ -95,8 +105,8 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
95
105
|
'oauthlint-rule-id': string;
|
|
96
106
|
'oauthlint-doc-url': string;
|
|
97
107
|
category: "security";
|
|
108
|
+
cwe: string;
|
|
98
109
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
99
|
-
cwe?: string | undefined;
|
|
100
110
|
owasp?: string | undefined;
|
|
101
111
|
references?: string[] | undefined;
|
|
102
112
|
technology?: string[] | undefined;
|
|
@@ -109,6 +119,10 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
109
119
|
'pattern-either-regex'?: string[] | undefined;
|
|
110
120
|
patterns?: unknown[] | undefined;
|
|
111
121
|
fix?: string | undefined;
|
|
122
|
+
paths?: {
|
|
123
|
+
include?: string[] | undefined;
|
|
124
|
+
exclude?: string[] | undefined;
|
|
125
|
+
} | undefined;
|
|
112
126
|
mode?: "search" | "taint" | undefined;
|
|
113
127
|
'pattern-sources'?: unknown[] | undefined;
|
|
114
128
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -123,8 +137,8 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
123
137
|
'oauthlint-rule-id': string;
|
|
124
138
|
'oauthlint-doc-url': string;
|
|
125
139
|
category: "security";
|
|
140
|
+
cwe: string;
|
|
126
141
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
127
|
-
cwe?: string | undefined;
|
|
128
142
|
owasp?: string | undefined;
|
|
129
143
|
references?: string[] | undefined;
|
|
130
144
|
technology?: string[] | undefined;
|
|
@@ -137,6 +151,10 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
137
151
|
'pattern-either-regex'?: string[] | undefined;
|
|
138
152
|
patterns?: unknown[] | undefined;
|
|
139
153
|
fix?: string | undefined;
|
|
154
|
+
paths?: {
|
|
155
|
+
include?: string[] | undefined;
|
|
156
|
+
exclude?: string[] | undefined;
|
|
157
|
+
} | undefined;
|
|
140
158
|
mode?: "search" | "taint" | undefined;
|
|
141
159
|
'pattern-sources'?: unknown[] | undefined;
|
|
142
160
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -151,8 +169,8 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
151
169
|
'oauthlint-rule-id': string;
|
|
152
170
|
'oauthlint-doc-url': string;
|
|
153
171
|
category: "security";
|
|
172
|
+
cwe: string;
|
|
154
173
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
155
|
-
cwe?: string | undefined;
|
|
156
174
|
owasp?: string | undefined;
|
|
157
175
|
references?: string[] | undefined;
|
|
158
176
|
technology?: string[] | undefined;
|
|
@@ -165,6 +183,10 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
165
183
|
'pattern-either-regex'?: string[] | undefined;
|
|
166
184
|
patterns?: unknown[] | undefined;
|
|
167
185
|
fix?: string | undefined;
|
|
186
|
+
paths?: {
|
|
187
|
+
include?: string[] | undefined;
|
|
188
|
+
exclude?: string[] | undefined;
|
|
189
|
+
} | undefined;
|
|
168
190
|
mode?: "search" | "taint" | undefined;
|
|
169
191
|
'pattern-sources'?: unknown[] | undefined;
|
|
170
192
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -179,8 +201,8 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
179
201
|
'oauthlint-rule-id': string;
|
|
180
202
|
'oauthlint-doc-url': string;
|
|
181
203
|
category: "security";
|
|
204
|
+
cwe: string;
|
|
182
205
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
183
|
-
cwe?: string | undefined;
|
|
184
206
|
owasp?: string | undefined;
|
|
185
207
|
references?: string[] | undefined;
|
|
186
208
|
technology?: string[] | undefined;
|
|
@@ -193,6 +215,10 @@ export declare const RuleSchema: z.ZodEffects<z.ZodObject<{
|
|
|
193
215
|
'pattern-either-regex'?: string[] | undefined;
|
|
194
216
|
patterns?: unknown[] | undefined;
|
|
195
217
|
fix?: string | undefined;
|
|
218
|
+
paths?: {
|
|
219
|
+
include?: string[] | undefined;
|
|
220
|
+
exclude?: string[] | undefined;
|
|
221
|
+
} | undefined;
|
|
196
222
|
mode?: "search" | "taint" | undefined;
|
|
197
223
|
'pattern-sources'?: unknown[] | undefined;
|
|
198
224
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -210,7 +236,7 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
210
236
|
'oauthlint-rule-id': z.ZodString;
|
|
211
237
|
'oauthlint-doc-url': z.ZodString;
|
|
212
238
|
category: z.ZodLiteral<"security">;
|
|
213
|
-
cwe: z.
|
|
239
|
+
cwe: z.ZodString;
|
|
214
240
|
owasp: z.ZodOptional<z.ZodString>;
|
|
215
241
|
'llm-prevalence': z.ZodEnum<["HIGH", "MEDIUM", "LOW"]>;
|
|
216
242
|
references: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -219,8 +245,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
219
245
|
'oauthlint-rule-id': string;
|
|
220
246
|
'oauthlint-doc-url': string;
|
|
221
247
|
category: "security";
|
|
248
|
+
cwe: string;
|
|
222
249
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
223
|
-
cwe?: string | undefined;
|
|
224
250
|
owasp?: string | undefined;
|
|
225
251
|
references?: string[] | undefined;
|
|
226
252
|
technology?: string[] | undefined;
|
|
@@ -228,8 +254,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
228
254
|
'oauthlint-rule-id': string;
|
|
229
255
|
'oauthlint-doc-url': string;
|
|
230
256
|
category: "security";
|
|
257
|
+
cwe: string;
|
|
231
258
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
232
|
-
cwe?: string | undefined;
|
|
233
259
|
owasp?: string | undefined;
|
|
234
260
|
references?: string[] | undefined;
|
|
235
261
|
technology?: string[] | undefined;
|
|
@@ -242,6 +268,16 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
242
268
|
'pattern-either-regex': z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
243
269
|
patterns: z.ZodOptional<z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">>;
|
|
244
270
|
fix: z.ZodOptional<z.ZodString>;
|
|
271
|
+
paths: z.ZodOptional<z.ZodObject<{
|
|
272
|
+
include: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
273
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
274
|
+
}, "strip", z.ZodTypeAny, {
|
|
275
|
+
include?: string[] | undefined;
|
|
276
|
+
exclude?: string[] | undefined;
|
|
277
|
+
}, {
|
|
278
|
+
include?: string[] | undefined;
|
|
279
|
+
exclude?: string[] | undefined;
|
|
280
|
+
}>>;
|
|
245
281
|
mode: z.ZodOptional<z.ZodEnum<["search", "taint"]>>;
|
|
246
282
|
'pattern-sources': z.ZodOptional<z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">>;
|
|
247
283
|
'pattern-sinks': z.ZodOptional<z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">>;
|
|
@@ -256,8 +292,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
256
292
|
'oauthlint-rule-id': string;
|
|
257
293
|
'oauthlint-doc-url': string;
|
|
258
294
|
category: "security";
|
|
295
|
+
cwe: string;
|
|
259
296
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
260
|
-
cwe?: string | undefined;
|
|
261
297
|
owasp?: string | undefined;
|
|
262
298
|
references?: string[] | undefined;
|
|
263
299
|
technology?: string[] | undefined;
|
|
@@ -270,6 +306,10 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
270
306
|
'pattern-either-regex'?: string[] | undefined;
|
|
271
307
|
patterns?: unknown[] | undefined;
|
|
272
308
|
fix?: string | undefined;
|
|
309
|
+
paths?: {
|
|
310
|
+
include?: string[] | undefined;
|
|
311
|
+
exclude?: string[] | undefined;
|
|
312
|
+
} | undefined;
|
|
273
313
|
mode?: "search" | "taint" | undefined;
|
|
274
314
|
'pattern-sources'?: unknown[] | undefined;
|
|
275
315
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -284,8 +324,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
284
324
|
'oauthlint-rule-id': string;
|
|
285
325
|
'oauthlint-doc-url': string;
|
|
286
326
|
category: "security";
|
|
327
|
+
cwe: string;
|
|
287
328
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
288
|
-
cwe?: string | undefined;
|
|
289
329
|
owasp?: string | undefined;
|
|
290
330
|
references?: string[] | undefined;
|
|
291
331
|
technology?: string[] | undefined;
|
|
@@ -298,6 +338,10 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
298
338
|
'pattern-either-regex'?: string[] | undefined;
|
|
299
339
|
patterns?: unknown[] | undefined;
|
|
300
340
|
fix?: string | undefined;
|
|
341
|
+
paths?: {
|
|
342
|
+
include?: string[] | undefined;
|
|
343
|
+
exclude?: string[] | undefined;
|
|
344
|
+
} | undefined;
|
|
301
345
|
mode?: "search" | "taint" | undefined;
|
|
302
346
|
'pattern-sources'?: unknown[] | undefined;
|
|
303
347
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -312,8 +356,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
312
356
|
'oauthlint-rule-id': string;
|
|
313
357
|
'oauthlint-doc-url': string;
|
|
314
358
|
category: "security";
|
|
359
|
+
cwe: string;
|
|
315
360
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
316
|
-
cwe?: string | undefined;
|
|
317
361
|
owasp?: string | undefined;
|
|
318
362
|
references?: string[] | undefined;
|
|
319
363
|
technology?: string[] | undefined;
|
|
@@ -326,6 +370,10 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
326
370
|
'pattern-either-regex'?: string[] | undefined;
|
|
327
371
|
patterns?: unknown[] | undefined;
|
|
328
372
|
fix?: string | undefined;
|
|
373
|
+
paths?: {
|
|
374
|
+
include?: string[] | undefined;
|
|
375
|
+
exclude?: string[] | undefined;
|
|
376
|
+
} | undefined;
|
|
329
377
|
mode?: "search" | "taint" | undefined;
|
|
330
378
|
'pattern-sources'?: unknown[] | undefined;
|
|
331
379
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -340,8 +388,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
340
388
|
'oauthlint-rule-id': string;
|
|
341
389
|
'oauthlint-doc-url': string;
|
|
342
390
|
category: "security";
|
|
391
|
+
cwe: string;
|
|
343
392
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
344
|
-
cwe?: string | undefined;
|
|
345
393
|
owasp?: string | undefined;
|
|
346
394
|
references?: string[] | undefined;
|
|
347
395
|
technology?: string[] | undefined;
|
|
@@ -354,6 +402,10 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
354
402
|
'pattern-either-regex'?: string[] | undefined;
|
|
355
403
|
patterns?: unknown[] | undefined;
|
|
356
404
|
fix?: string | undefined;
|
|
405
|
+
paths?: {
|
|
406
|
+
include?: string[] | undefined;
|
|
407
|
+
exclude?: string[] | undefined;
|
|
408
|
+
} | undefined;
|
|
357
409
|
mode?: "search" | "taint" | undefined;
|
|
358
410
|
'pattern-sources'?: unknown[] | undefined;
|
|
359
411
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -370,8 +422,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
370
422
|
'oauthlint-rule-id': string;
|
|
371
423
|
'oauthlint-doc-url': string;
|
|
372
424
|
category: "security";
|
|
425
|
+
cwe: string;
|
|
373
426
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
374
|
-
cwe?: string | undefined;
|
|
375
427
|
owasp?: string | undefined;
|
|
376
428
|
references?: string[] | undefined;
|
|
377
429
|
technology?: string[] | undefined;
|
|
@@ -384,6 +436,10 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
384
436
|
'pattern-either-regex'?: string[] | undefined;
|
|
385
437
|
patterns?: unknown[] | undefined;
|
|
386
438
|
fix?: string | undefined;
|
|
439
|
+
paths?: {
|
|
440
|
+
include?: string[] | undefined;
|
|
441
|
+
exclude?: string[] | undefined;
|
|
442
|
+
} | undefined;
|
|
387
443
|
mode?: "search" | "taint" | undefined;
|
|
388
444
|
'pattern-sources'?: unknown[] | undefined;
|
|
389
445
|
'pattern-sinks'?: unknown[] | undefined;
|
|
@@ -400,8 +456,8 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
400
456
|
'oauthlint-rule-id': string;
|
|
401
457
|
'oauthlint-doc-url': string;
|
|
402
458
|
category: "security";
|
|
459
|
+
cwe: string;
|
|
403
460
|
'llm-prevalence': "HIGH" | "MEDIUM" | "LOW";
|
|
404
|
-
cwe?: string | undefined;
|
|
405
461
|
owasp?: string | undefined;
|
|
406
462
|
references?: string[] | undefined;
|
|
407
463
|
technology?: string[] | undefined;
|
|
@@ -414,6 +470,10 @@ export declare const RuleFileSchema: z.ZodObject<{
|
|
|
414
470
|
'pattern-either-regex'?: string[] | undefined;
|
|
415
471
|
patterns?: unknown[] | undefined;
|
|
416
472
|
fix?: string | undefined;
|
|
473
|
+
paths?: {
|
|
474
|
+
include?: string[] | undefined;
|
|
475
|
+
exclude?: string[] | undefined;
|
|
476
|
+
} | undefined;
|
|
417
477
|
mode?: "search" | "taint" | undefined;
|
|
418
478
|
'pattern-sources'?: unknown[] | undefined;
|
|
419
479
|
'pattern-sinks'?: unknown[] | undefined;
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,cAAc,yCAAuC,CAAC;AACnE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,cAAc,yCAAuC,CAAC;AACnE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAclC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAqBxE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CpB,CAAC;AAEJ,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
package/dist/schema.js
CHANGED
|
@@ -18,10 +18,7 @@ export const OAuthLintMetadataSchema = z.object({
|
|
|
18
18
|
}),
|
|
19
19
|
'oauthlint-doc-url': z.string().url(),
|
|
20
20
|
category: z.literal('security'),
|
|
21
|
-
cwe: z
|
|
22
|
-
.string()
|
|
23
|
-
.regex(/^CWE-\d+$/)
|
|
24
|
-
.optional(),
|
|
21
|
+
cwe: z.string().regex(/^CWE-\d+$/),
|
|
25
22
|
owasp: z.string().optional(),
|
|
26
23
|
'llm-prevalence': z.enum(['HIGH', 'MEDIUM', 'LOW']),
|
|
27
24
|
references: z.array(z.string().url()).optional(),
|
|
@@ -32,6 +29,16 @@ export const OAuthLintMetadataSchema = z.object({
|
|
|
32
29
|
* Semgrep accepts many shapes; we only validate the fields we rely on.
|
|
33
30
|
*/
|
|
34
31
|
const PatternEntrySchema = z.lazy(() => z.union([z.string(), z.record(z.string(), z.unknown()), z.array(PatternEntrySchema)]));
|
|
32
|
+
/**
|
|
33
|
+
* Semgrep `paths:` filter. Lets a rule scope itself to (or away from) files by
|
|
34
|
+
* glob. We use `exclude` to keep production-grant rules from firing on test,
|
|
35
|
+
* example, vendored, or generated code — locations that should never carry a
|
|
36
|
+
* real application's OAuth misuse. Passed straight through to Semgrep.
|
|
37
|
+
*/
|
|
38
|
+
const PathsSchema = z.object({
|
|
39
|
+
include: z.array(z.string()).optional(),
|
|
40
|
+
exclude: z.array(z.string()).optional(),
|
|
41
|
+
});
|
|
35
42
|
export const RuleSchema = z
|
|
36
43
|
.object({
|
|
37
44
|
// auth.<category>.<name> for the JS/TS pack; language packs prepend a
|
|
@@ -53,6 +60,8 @@ export const RuleSchema = z
|
|
|
53
60
|
'pattern-either-regex': z.array(z.string()).optional(),
|
|
54
61
|
patterns: z.array(PatternEntrySchema).optional(),
|
|
55
62
|
fix: z.string().optional(),
|
|
63
|
+
// Scope a rule to/away from files by glob (passed through to Semgrep).
|
|
64
|
+
paths: PathsSchema.optional(),
|
|
56
65
|
// Taint-mode rules (Semgrep dataflow).
|
|
57
66
|
mode: z.enum(['search', 'taint']).optional(),
|
|
58
67
|
'pattern-sources': z.array(PatternEntrySchema).optional(),
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AAGnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,yEAAyE;IACzE,uDAAuD;IACvD,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,+BAA+B,EAAE;QACrE,OAAO,EACL,8FAA8F;KACjG,CAAC;IACF,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACrC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IAC/B,GAAG,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AAGnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,yEAAyE;IACzE,uDAAuD;IACvD,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,+BAA+B,EAAE;QACrE,OAAO,EACL,8FAA8F;KACjG,CAAC;IACF,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACrC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IAC/B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE;IAChD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC3C,CAAC,CAAC;AAIH;;;GAGG;AACH,MAAM,kBAAkB,GAAuB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CACzD,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,CACtF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACvC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC;KACxB,MAAM,CAAC;IACN,sEAAsE;IACtE,iFAAiF;IACjF,qEAAqE;IACrE,0EAA0E;IAC1E,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,6DAA6D,EAAE;QAClF,OAAO,EACL,0FAA0F;KAC7F,CAAC;IACF,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,QAAQ,EAAE,cAAc;IACxB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,wCAAwC,CAAC;IACrE,QAAQ,EAAE,uBAAuB;IACjC,OAAO,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACtC,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IACxD,aAAa,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IAC5C,gBAAgB,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IAC/C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACtC,sBAAsB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IAChD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,uEAAuE;IACvE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;IAC7B,uCAAuC;IACvC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC5C,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IACzD,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IACvD,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;IAC5D,qBAAqB,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE;CAC9D,CAAC;KACD,MAAM,CACL,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,OAAO,KAAK,SAAS;IAC1B,IAAI,CAAC,gBAAgB,CAAC,KAAK,SAAS;IACpC,IAAI,CAAC,QAAQ,KAAK,SAAS;IAC3B,IAAI,CAAC,eAAe,CAAC,KAAK,SAAS;IACnC,IAAI,CAAC,sBAAsB,CAAC,KAAK,SAAS;IAC1C,qEAAqE;IACrE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO;QACpB,IAAI,CAAC,iBAAiB,CAAC,KAAK,SAAS;QACrC,IAAI,CAAC,eAAe,CAAC,KAAK,SAAS,CAAC,EACxC;IACE,OAAO,EACL,6IAA6I;CAChJ,CACF,CAAC;AAIJ,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAClC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,6 +4,28 @@ rules:
|
|
|
4
4
|
- javascript
|
|
5
5
|
- typescript
|
|
6
6
|
severity: WARNING
|
|
7
|
+
# Non-production code (example apps, demos, docs, vendored copies, tests)
|
|
8
|
+
# is not the library surface users ship, so findings there are noise for a
|
|
9
|
+
# low-FP linter. In particular this skips vendored third-party cookie
|
|
10
|
+
# serializers (e.g. packages/core/src/lib/vendored/cookie.ts) whose
|
|
11
|
+
# incremental `"; SameSite=None"` attribute fragment is not a complete
|
|
12
|
+
# insecure cookie. Globs intentionally omit `**/tests/**` / `**/fixtures/**`
|
|
13
|
+
# so the rule still fires on its own fixtures under rules/tests/fixtures/.
|
|
14
|
+
paths:
|
|
15
|
+
exclude:
|
|
16
|
+
- "**/test/**"
|
|
17
|
+
- "**/__tests__/**"
|
|
18
|
+
- "**/*.test.*"
|
|
19
|
+
- "**/*.spec.*"
|
|
20
|
+
- "**/example/**"
|
|
21
|
+
- "**/examples/**"
|
|
22
|
+
- "**/apps/**"
|
|
23
|
+
- "**/docs/**"
|
|
24
|
+
- "**/__mocks__/**"
|
|
25
|
+
- "**/mocks/**"
|
|
26
|
+
- "**/vendored/**"
|
|
27
|
+
- "**/node_modules/**"
|
|
28
|
+
- "**/*.stories.*"
|
|
7
29
|
message: |
|
|
8
30
|
A cookie is being set with `SameSite=None` but WITHOUT `Secure`.
|
|
9
31
|
`SameSite=None` *requires* `Secure`: modern browsers reject a
|
|
@@ -40,7 +62,7 @@ rules:
|
|
|
40
62
|
oauthlint-doc-url: https://oauthlint.dev/rules/cookie-samesite-none-insecure
|
|
41
63
|
category: security
|
|
42
64
|
cwe: CWE-1275
|
|
43
|
-
owasp:
|
|
65
|
+
owasp: API8:2023
|
|
44
66
|
llm-prevalence: MEDIUM
|
|
45
67
|
technology:
|
|
46
68
|
- express
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
- id: auth.flow.basic-auth-in-log
|
|
3
|
+
languages:
|
|
4
|
+
- javascript
|
|
5
|
+
- typescript
|
|
6
|
+
severity: ERROR
|
|
7
|
+
message: |
|
|
8
|
+
HTTP Basic credentials flow into a logging call (`console.*` or
|
|
9
|
+
`logger.*`). The `basic-auth` package returns the decoded `{ name, pass }`
|
|
10
|
+
for the request, and the `Proxy-Authorization` header carries
|
|
11
|
+
base64-encoded `user:password` just like `Authorization` does. Logs are
|
|
12
|
+
written to files, shipped to aggregators (Datadog, Splunk, CloudWatch) and
|
|
13
|
+
read by people and systems that should never see live credentials — the
|
|
14
|
+
base64 is trivially reversible, so a logged Basic header or a logged
|
|
15
|
+
`creds.pass` is a plaintext password leak (CWE-532).
|
|
16
|
+
|
|
17
|
+
Never log the raw credential. Redact or mask it before logging, log a
|
|
18
|
+
non-sensitive identifier instead (the username alone, a user id), or drop
|
|
19
|
+
the field entirely.
|
|
20
|
+
# Taint mode so indirection is caught — `const creds = auth(req);
|
|
21
|
+
# logger.info(creds.pass)` flags, not just an inline log.
|
|
22
|
+
#
|
|
23
|
+
# SCOPE / non-duplication: auth.flow.oauth-credential-in-log already covers
|
|
24
|
+
# the raw `Authorization` header (`req.headers.authorization`,
|
|
25
|
+
# `req.get('authorization')`, `req.header('authorization')`) flowing into a
|
|
26
|
+
# log, so this rule deliberately does NOT re-list those sources. It adds the
|
|
27
|
+
# genuinely-uncovered Basic-auth sources: the `basic-auth` package's parse
|
|
28
|
+
# result (`auth(req)` / `basicAuth(req)`, incl. `.name` / `.pass`) and the
|
|
29
|
+
# `Proxy-Authorization` header. Routing the value through a redaction /
|
|
30
|
+
# masking helper or a truncating slice clears the taint.
|
|
31
|
+
mode: taint
|
|
32
|
+
pattern-sources:
|
|
33
|
+
# `basic-auth` package: const credentials = auth(req) -> { name, pass }.
|
|
34
|
+
# $REQ is constrained to conventional request-object names so an unrelated
|
|
35
|
+
# `auth(user)` / `auth(config)` call is not treated as a Basic-auth parse.
|
|
36
|
+
- patterns:
|
|
37
|
+
- pattern-either:
|
|
38
|
+
- pattern: auth($REQ)
|
|
39
|
+
- pattern: basicAuth($REQ)
|
|
40
|
+
- pattern: auth($REQ).pass
|
|
41
|
+
- pattern: auth($REQ).name
|
|
42
|
+
- pattern: basicAuth($REQ).pass
|
|
43
|
+
- pattern: basicAuth($REQ).name
|
|
44
|
+
- metavariable-regex:
|
|
45
|
+
metavariable: $REQ
|
|
46
|
+
regex: ^(req|request|ctx|context|c|r)$
|
|
47
|
+
# Proxy-Authorization header (base64 user:password, like Authorization).
|
|
48
|
+
- pattern: $REQ.headers['proxy-authorization']
|
|
49
|
+
- pattern: $REQ.headers["proxy-authorization"]
|
|
50
|
+
- pattern: $REQ.get('proxy-authorization')
|
|
51
|
+
- pattern: $REQ.get('Proxy-Authorization')
|
|
52
|
+
- pattern: $REQ.header('proxy-authorization')
|
|
53
|
+
- pattern: $REQ.header('Proxy-Authorization')
|
|
54
|
+
pattern-sanitizers:
|
|
55
|
+
# The username is not a secret: reading `.name` / `.username` off the
|
|
56
|
+
# decoded Basic credentials clears the taint, so logging only the username
|
|
57
|
+
# (`creds.name`) does not fire — only the password / raw header does.
|
|
58
|
+
- pattern: $C.name
|
|
59
|
+
- pattern: $C.username
|
|
60
|
+
# Redaction / masking helpers, or a truncating slice/substring — the value
|
|
61
|
+
# that reaches the log is no longer the live credential.
|
|
62
|
+
- pattern: redact(...)
|
|
63
|
+
- pattern: mask(...)
|
|
64
|
+
- pattern: maskToken(...)
|
|
65
|
+
- pattern: $S.slice(...)
|
|
66
|
+
- pattern: $S.substring(...)
|
|
67
|
+
- pattern: $S.substr(...)
|
|
68
|
+
pattern-sinks:
|
|
69
|
+
# console.log/info/debug/warn/error(...) — any tainted argument fires.
|
|
70
|
+
- patterns:
|
|
71
|
+
- pattern-either:
|
|
72
|
+
- pattern: console.log(...)
|
|
73
|
+
- pattern: console.info(...)
|
|
74
|
+
- pattern: console.debug(...)
|
|
75
|
+
- pattern: console.warn(...)
|
|
76
|
+
- pattern: console.error(...)
|
|
77
|
+
# logger.<level>(...) — a log-named receiver with a log-level method.
|
|
78
|
+
- patterns:
|
|
79
|
+
- pattern: $LOG.$LEVEL(...)
|
|
80
|
+
- metavariable-regex:
|
|
81
|
+
metavariable: $LOG
|
|
82
|
+
regex: (?i)^.*log(?:ger)?$
|
|
83
|
+
- metavariable-regex:
|
|
84
|
+
metavariable: $LEVEL
|
|
85
|
+
regex: ^(?:log|info|debug|warn|warning|error|trace|fatal|verbose|silly)$
|
|
86
|
+
metadata:
|
|
87
|
+
oauthlint-rule-id: AUTH-FLOW-014
|
|
88
|
+
oauthlint-doc-url: https://oauthlint.dev/rules/flow-basic-auth-in-log
|
|
89
|
+
category: security
|
|
90
|
+
cwe: CWE-532
|
|
91
|
+
owasp: API8:2023
|
|
92
|
+
llm-prevalence: MEDIUM
|
|
93
|
+
technology:
|
|
94
|
+
- express
|
|
95
|
+
- basic-auth
|
|
96
|
+
references:
|
|
97
|
+
- https://cwe.mitre.org/data/definitions/532.html
|
|
98
|
+
- https://www.npmjs.com/package/basic-auth
|
|
99
|
+
- https://owasp.org/API-Security/editions/2023/en/0xa8-security-misconfiguration/
|
|
@@ -22,34 +22,55 @@ rules:
|
|
|
22
22
|
# (isAllowedUrl, allowlist.includes, Set.has) clears the taint, so a
|
|
23
23
|
# genuinely validated redirect does not fire.
|
|
24
24
|
mode: taint
|
|
25
|
+
# `$REQ` is constrained to conventional request-object names so that
|
|
26
|
+
# unrelated receivers (`db.query`, `config.headers`, `someObj.body`) are not
|
|
27
|
+
# treated as untrusted request input.
|
|
25
28
|
pattern-sources:
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
- patterns:
|
|
30
|
+
- pattern-either:
|
|
31
|
+
- pattern: $REQ.query
|
|
32
|
+
- pattern: $REQ.params
|
|
33
|
+
- pattern: $REQ.body
|
|
34
|
+
- pattern: $REQ.cookies
|
|
35
|
+
- pattern: $REQ.headers
|
|
36
|
+
- pattern: $REQ.query.$X
|
|
37
|
+
- pattern: $REQ.params.$X
|
|
38
|
+
- pattern: $REQ.body.$X
|
|
39
|
+
- pattern: $REQ.cookies.$X
|
|
40
|
+
- pattern: $REQ.headers.$X
|
|
41
|
+
- pattern: $REQ.query[$K]
|
|
42
|
+
- pattern: $REQ.params[$K]
|
|
43
|
+
- pattern: $REQ.body[$K]
|
|
44
|
+
- pattern: $REQ.cookies[$K]
|
|
45
|
+
- pattern: $REQ.headers[$K]
|
|
46
|
+
- metavariable-regex:
|
|
47
|
+
metavariable: $REQ
|
|
48
|
+
regex: ^(req|request|ctx|context|c|event|r)$
|
|
41
49
|
pattern-sanitizers:
|
|
42
50
|
# Routing the value through an allow-list / validation helper clears the
|
|
43
51
|
# taint: only the vetted result (not the raw request input) reaches the
|
|
44
|
-
# sink.
|
|
45
|
-
# allow-list membership test (`Set.has` / `Array.includes`) that the
|
|
46
|
-
# value is passed through.
|
|
52
|
+
# sink.
|
|
47
53
|
- pattern: isAllowedUrl(...)
|
|
48
54
|
- pattern: validateRedirect(...)
|
|
49
55
|
- pattern: sanitizeRedirect(...)
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
# An inline allow-list membership guard vets the value: a value used inside
|
|
57
|
+
# `if (allow.has(x)) { ... }` / `if (allow.includes(x)) { ... }` /
|
|
58
|
+
# `if (allow.indexOf(x) ...) { ... }` is treated as validated. The
|
|
59
|
+
# boolean-returning membership call itself does NOT sanitize its argument
|
|
60
|
+
# (that would only clear the boolean, not the value), so we clear taint by
|
|
61
|
+
# the if-guard, mirroring the Python rule's `if is_safe_url(v): ...`.
|
|
62
|
+
- patterns:
|
|
63
|
+
- pattern: $X
|
|
64
|
+
- pattern-inside: |
|
|
65
|
+
if (<... $ALLOW.has($X) ...>) { ... }
|
|
66
|
+
- patterns:
|
|
67
|
+
- pattern: $X
|
|
68
|
+
- pattern-inside: |
|
|
69
|
+
if (<... $ALLOW.includes($X) ...>) { ... }
|
|
70
|
+
- patterns:
|
|
71
|
+
- pattern: $X
|
|
72
|
+
- pattern-inside: |
|
|
73
|
+
if (<... $ALLOW.indexOf($X) ...>) { ... }
|
|
53
74
|
pattern-sinks:
|
|
54
75
|
- patterns:
|
|
55
76
|
- pattern-either:
|
|
@@ -61,6 +82,17 @@ rules:
|
|
|
61
82
|
- pattern: "$RES.setHeader('Location', $SINK)"
|
|
62
83
|
- pattern: '$RES.setHeader("Location", $SINK)'
|
|
63
84
|
- pattern: "$RES.writeHead($S, {..., Location: $SINK, ...})"
|
|
85
|
+
# `$RES.redirect(...)` / `$RES.location(...)` also match a bare,
|
|
86
|
+
# receiver-less `redirect(...)` / `location(...)` call. Those are the
|
|
87
|
+
# framework navigation primitives exported by Next.js
|
|
88
|
+
# (`next/navigation`), SvelteKit and Remix — they send the user to a
|
|
89
|
+
# server-constructed application URL, not the Express `res.redirect`
|
|
90
|
+
# open-redirect sink this rule targets. Requiring an explicit receiver
|
|
91
|
+
# removes that over-match (the dominant FP class seen on next-auth)
|
|
92
|
+
# without affecting any `res.redirect` / `res.location` detection.
|
|
93
|
+
- pattern-not: redirect($SINK)
|
|
94
|
+
- pattern-not: redirect($CODE, $SINK)
|
|
95
|
+
- pattern-not: location($SINK)
|
|
64
96
|
- focus-metavariable: $SINK
|
|
65
97
|
metadata:
|
|
66
98
|
oauthlint-rule-id: AUTH-FLOW-010
|