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.
Files changed (39) hide show
  1. package/dist/loader.d.ts +1 -1
  2. package/dist/schema.d.ts +79 -19
  3. package/dist/schema.d.ts.map +1 -1
  4. package/dist/schema.js +13 -4
  5. package/dist/schema.js.map +1 -1
  6. package/package.json +1 -1
  7. package/rules/cookie/no-samesite.yml +1 -1
  8. package/rules/cookie/samesite-none-insecure.yml +23 -1
  9. package/rules/cors/null-origin.yml +1 -1
  10. package/rules/cors/reflect-origin.yml +1 -1
  11. package/rules/flow/basic-auth-in-log.yml +99 -0
  12. package/rules/flow/open-redirect.yml +53 -21
  13. package/rules/flow/ssrf.yml +61 -21
  14. package/rules/flow/timing-unsafe-compare.yml +19 -0
  15. package/rules/go/cookie/insecure.yml +1 -1
  16. package/rules/go/cors/allow-all.yml +1 -1
  17. package/rules/go/flow/open-redirect.yml +16 -6
  18. package/rules/go/flow/ssrf.yml +16 -7
  19. package/rules/go/oauth/ropc-grant.yml +15 -0
  20. package/rules/java/cookie/insecure.yml +1 -1
  21. package/rules/java/cors/allow-all.yml +1 -1
  22. package/rules/java/cors/credentialed-wildcard.yml +1 -1
  23. package/rules/java/flow/ssrf.yml +113 -0
  24. package/rules/java/session/fixation-disabled.yml +1 -1
  25. package/rules/java/tls/trust-all-certs.yml +18 -7
  26. package/rules/oauth/no-state.yml +9 -8
  27. package/rules/oauth/open-redirect-callback.yml +18 -3
  28. package/rules/oauth/ropc-grant.yml +8 -3
  29. package/rules/oauth/static-state.yml +8 -7
  30. package/rules/py/cookie/insecure-flags.yml +1 -1
  31. package/rules/py/cors/allow-all.yml +1 -1
  32. package/rules/py/flow/requests-verify-disabled.yml +1 -1
  33. package/rules/py/oauth/ropc-grant.yml +12 -4
  34. package/rules/rust/cookie/insecure.yml +1 -1
  35. package/rules/rust/cors/permissive.yml +1 -1
  36. package/rules/rust/flow/ssrf.yml +90 -0
  37. package/rules/rust/oauth/ropc-grant.yml +17 -0
  38. package/rules/rust/oauth/static-state.yml +25 -5
  39. 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 | undefined;
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.ZodOptional<z.ZodString>;
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.ZodOptional<z.ZodString>;
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.ZodOptional<z.ZodString>;
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;
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBlC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAUxE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CpB,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"}
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(),
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oauthlint-rules",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Semgrep rules catching the OAuth/OIDC/JWT anti-patterns that AI coding tools systematically produce.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,7 +51,7 @@ rules:
51
51
  oauthlint-doc-url: https://oauthlint.dev/rules/cookie-no-samesite
52
52
  category: security
53
53
  cwe: CWE-1275
54
- owasp: API1:2023
54
+ owasp: API8:2023
55
55
  llm-prevalence: MEDIUM
56
56
  technology:
57
57
  - express
@@ -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: A05:2021
65
+ owasp: API8:2023
44
66
  llm-prevalence: MEDIUM
45
67
  technology:
46
68
  - express
@@ -43,7 +43,7 @@ rules:
43
43
  oauthlint-doc-url: https://oauthlint.dev/rules/cors-null-origin
44
44
  category: security
45
45
  cwe: CWE-942
46
- owasp: A05:2021
46
+ owasp: API8:2023
47
47
  llm-prevalence: MEDIUM
48
48
  technology:
49
49
  - cors
@@ -68,7 +68,7 @@ rules:
68
68
  oauthlint-doc-url: https://oauthlint.dev/rules/cors-reflect-origin
69
69
  category: security
70
70
  cwe: CWE-942
71
- owasp: A05:2021
71
+ owasp: API8:2023
72
72
  llm-prevalence: MEDIUM
73
73
  technology:
74
74
  - cors
@@ -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
- - pattern: $REQ.query
27
- - pattern: $REQ.params
28
- - pattern: $REQ.body
29
- - pattern: $REQ.cookies
30
- - pattern: $REQ.headers
31
- - pattern: $REQ.query.$X
32
- - pattern: $REQ.params.$X
33
- - pattern: $REQ.body.$X
34
- - pattern: $REQ.cookies.$X
35
- - pattern: $REQ.headers.$X
36
- - pattern: $REQ.query[$K]
37
- - pattern: $REQ.params[$K]
38
- - pattern: $REQ.body[$K]
39
- - pattern: $REQ.cookies[$K]
40
- - pattern: $REQ.headers[$K]
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. Matched by a conventional validation-helper call, or by an
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
- - pattern: $ALLOW.includes(...)
51
- - pattern: $ALLOW.has(...)
52
- - pattern: $ALLOW.indexOf(...)
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