@reliabilityworks/ruleset-nextjs 0.2.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/package.json +1 -1
- package/rules.json +684 -0
package/package.json
CHANGED
package/rules.json
CHANGED
|
@@ -11,6 +11,186 @@
|
|
|
11
11
|
"message": "productionBrowserSourceMaps appears to be enabled"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
"id": "nextjs/poweredbyheader-enabled",
|
|
16
|
+
"severity": "low",
|
|
17
|
+
"title": "X-Powered-By header enabled",
|
|
18
|
+
"description": "The X-Powered-By header can reveal implementation details. Consider disabling it in production.",
|
|
19
|
+
"matcher": {
|
|
20
|
+
"type": "regex",
|
|
21
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
22
|
+
"pattern": "poweredByHeader\\s*:\\s*true",
|
|
23
|
+
"message": "poweredByHeader appears to be enabled"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "nextjs/react-strict-mode-disabled",
|
|
28
|
+
"severity": "low",
|
|
29
|
+
"title": "React strict mode disabled",
|
|
30
|
+
"description": "Disabling React strict mode can reduce signals during development and may allow risky patterns to persist.",
|
|
31
|
+
"matcher": {
|
|
32
|
+
"type": "regex",
|
|
33
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
34
|
+
"pattern": "reactStrictMode\\s*:\\s*false",
|
|
35
|
+
"message": "reactStrictMode appears to be disabled"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "nextjs/compress-disabled",
|
|
40
|
+
"severity": "low",
|
|
41
|
+
"title": "HTTP compression disabled",
|
|
42
|
+
"description": "Disabling compression can increase response sizes and degrade performance.",
|
|
43
|
+
"matcher": {
|
|
44
|
+
"type": "regex",
|
|
45
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
46
|
+
"pattern": "\\bcompress\\s*:\\s*false",
|
|
47
|
+
"message": "compress appears to be disabled"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "nextjs/asset-prefix-http",
|
|
52
|
+
"severity": "medium",
|
|
53
|
+
"title": "assetPrefix uses plain HTTP",
|
|
54
|
+
"description": "Using an HTTP assetPrefix can enable MITM attacks on static assets.",
|
|
55
|
+
"matcher": {
|
|
56
|
+
"type": "regex",
|
|
57
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
58
|
+
"pattern": "assetPrefix\\s*:\\s*['\"]http://",
|
|
59
|
+
"message": "assetPrefix appears to be configured with http://"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "nextjs/typescript-ignore-build-errors",
|
|
64
|
+
"severity": "high",
|
|
65
|
+
"title": "TypeScript build errors ignored",
|
|
66
|
+
"description": "Ignoring TypeScript build errors can allow unsafe or broken code paths to ship to production.",
|
|
67
|
+
"matcher": {
|
|
68
|
+
"type": "regex",
|
|
69
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
70
|
+
"pattern": "typescript\\s*:\\s*\\{[^}]*\\bignoreBuildErrors\\s*:\\s*true",
|
|
71
|
+
"flags": "s",
|
|
72
|
+
"message": "typescript.ignoreBuildErrors appears to be enabled"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "nextjs/eslint-ignore-during-builds",
|
|
77
|
+
"severity": "medium",
|
|
78
|
+
"title": "ESLint checks ignored during builds",
|
|
79
|
+
"description": "Ignoring ESLint checks during builds can let insecure patterns ship undetected.",
|
|
80
|
+
"matcher": {
|
|
81
|
+
"type": "regex",
|
|
82
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
83
|
+
"pattern": "eslint\\s*:\\s*\\{[^}]*\\bignoreDuringBuilds\\s*:\\s*true",
|
|
84
|
+
"flags": "s",
|
|
85
|
+
"message": "eslint.ignoreDuringBuilds appears to be enabled"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "nextjs/images-dangerously-allow-svg",
|
|
90
|
+
"severity": "high",
|
|
91
|
+
"title": "SVGs allowed in next/image",
|
|
92
|
+
"description": "Allowing SVGs can increase XSS risk if SVG content is not tightly controlled.",
|
|
93
|
+
"matcher": {
|
|
94
|
+
"type": "regex",
|
|
95
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
96
|
+
"pattern": "dangerouslyAllowSVG\\s*:\\s*true",
|
|
97
|
+
"message": "images.dangerouslyAllowSVG appears to be enabled"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "nextjs/images-remote-http",
|
|
102
|
+
"severity": "medium",
|
|
103
|
+
"title": "Remote images allowed over HTTP",
|
|
104
|
+
"description": "Allowing remote images over HTTP can enable MITM attacks on image content.",
|
|
105
|
+
"matcher": {
|
|
106
|
+
"type": "regex",
|
|
107
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
108
|
+
"pattern": "protocol\\s*:\\s*['\"]http['\"]",
|
|
109
|
+
"message": "next/image remotePatterns appears to allow http"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "nextjs/images-domains-wildcard",
|
|
114
|
+
"severity": "medium",
|
|
115
|
+
"title": "Wildcard image domain configured",
|
|
116
|
+
"description": "Allowing images from any domain increases the risk of unexpected content and tracking.",
|
|
117
|
+
"matcher": {
|
|
118
|
+
"type": "regex",
|
|
119
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
120
|
+
"pattern": "domains\\s*:\\s*\\[[^\\]]*['\"]\\*['\"]",
|
|
121
|
+
"message": "images.domains appears to include a wildcard"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "nextjs/headers-cors-allow-origin-star",
|
|
126
|
+
"severity": "high",
|
|
127
|
+
"title": "CORS allow-origin '*' in next.config",
|
|
128
|
+
"description": "Allowing origin '*' can expose endpoints to cross-origin callers.",
|
|
129
|
+
"matcher": {
|
|
130
|
+
"type": "regex",
|
|
131
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
132
|
+
"pattern": "Access-Control-Allow-Origin[^\\n\\r]*\\bvalue\\s*:\\s*['\"]\\*['\"]",
|
|
133
|
+
"message": "Access-Control-Allow-Origin appears to be set to '*'"
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "nextjs/headers-cors-allow-credentials-true",
|
|
138
|
+
"severity": "high",
|
|
139
|
+
"title": "CORS allow-credentials true in next.config",
|
|
140
|
+
"description": "Allowing credentials in CORS responses can increase risk when combined with permissive origins.",
|
|
141
|
+
"matcher": {
|
|
142
|
+
"type": "regex",
|
|
143
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
144
|
+
"pattern": "Access-Control-Allow-Credentials[^\\n\\r]*\\bvalue\\s*:\\s*['\"]true['\"]",
|
|
145
|
+
"message": "Access-Control-Allow-Credentials appears to be enabled"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "nextjs/headers-cors-allow-headers-star",
|
|
150
|
+
"severity": "medium",
|
|
151
|
+
"title": "CORS allow-headers '*' in next.config",
|
|
152
|
+
"description": "Allowing any headers in CORS responses can broaden attack surface.",
|
|
153
|
+
"matcher": {
|
|
154
|
+
"type": "regex",
|
|
155
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
156
|
+
"pattern": "Access-Control-Allow-Headers[^\\n\\r]*\\bvalue\\s*:\\s*['\"]\\*['\"]",
|
|
157
|
+
"message": "Access-Control-Allow-Headers appears to be set to '*'"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"id": "nextjs/headers-cors-allow-methods-star",
|
|
162
|
+
"severity": "medium",
|
|
163
|
+
"title": "CORS allow-methods '*' in next.config",
|
|
164
|
+
"description": "Allowing any methods in CORS responses can broaden attack surface.",
|
|
165
|
+
"matcher": {
|
|
166
|
+
"type": "regex",
|
|
167
|
+
"fileGlobs": ["**/next.config.{js,cjs,mjs,ts}"],
|
|
168
|
+
"pattern": "Access-Control-Allow-Methods[^\\n\\r]*\\bvalue\\s*:\\s*['\"]\\*['\"]",
|
|
169
|
+
"message": "Access-Control-Allow-Methods appears to be set to '*'"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"id": "nextjs/public-source-maps",
|
|
174
|
+
"severity": "medium",
|
|
175
|
+
"title": "Source maps in public directory",
|
|
176
|
+
"description": "Shipping source maps in public/ can expose source code and application internals.",
|
|
177
|
+
"matcher": {
|
|
178
|
+
"type": "file_presence",
|
|
179
|
+
"paths": ["public/**/*.map"],
|
|
180
|
+
"message": "Source map file present under public/"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "nextjs/public-private-key-file",
|
|
185
|
+
"severity": "high",
|
|
186
|
+
"title": "Key material file in public directory",
|
|
187
|
+
"description": "Key files under public/ may be exposed to clients if served.",
|
|
188
|
+
"matcher": {
|
|
189
|
+
"type": "file_presence",
|
|
190
|
+
"paths": ["public/**/*.{pem,key}"],
|
|
191
|
+
"message": "Potential key file present under public/"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
14
194
|
{
|
|
15
195
|
"id": "nextjs/next-public-secret-name",
|
|
16
196
|
"severity": "high",
|
|
@@ -34,5 +214,509 @@
|
|
|
34
214
|
"pattern": "\\brevalidate\\s*:\\s*0\\b",
|
|
35
215
|
"message": "revalidate is set to 0"
|
|
36
216
|
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"id": "nextjs/dangerously-set-inner-html",
|
|
220
|
+
"severity": "medium",
|
|
221
|
+
"title": "dangerouslySetInnerHTML usage",
|
|
222
|
+
"description": "dangerouslySetInnerHTML renders raw HTML into the page. If the value is derived from user input, it can enable XSS unless sanitized.",
|
|
223
|
+
"matcher": {
|
|
224
|
+
"type": "regex",
|
|
225
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
226
|
+
"pattern": "dangerouslySetInnerHTML\\s*=\\s*\\{\\{",
|
|
227
|
+
"message": "dangerouslySetInnerHTML renders raw HTML; ensure the content is sanitized"
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"id": "nextjs/dom-innerhtml-assignment",
|
|
232
|
+
"severity": "medium",
|
|
233
|
+
"title": "innerHTML assignment",
|
|
234
|
+
"description": "Assigning to innerHTML can lead to XSS if the content is not sanitized.",
|
|
235
|
+
"matcher": {
|
|
236
|
+
"type": "regex",
|
|
237
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
238
|
+
"pattern": "\\binnerHTML\\s*=",
|
|
239
|
+
"message": "innerHTML assignment detected; ensure content is sanitized"
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"id": "nextjs/dom-outerhtml-assignment",
|
|
244
|
+
"severity": "medium",
|
|
245
|
+
"title": "outerHTML assignment",
|
|
246
|
+
"description": "Assigning to outerHTML can lead to XSS if the content is not sanitized.",
|
|
247
|
+
"matcher": {
|
|
248
|
+
"type": "regex",
|
|
249
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
250
|
+
"pattern": "\\bouterHTML\\s*=",
|
|
251
|
+
"message": "outerHTML assignment detected; ensure content is sanitized"
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"id": "nextjs/dom-insertadjacenthtml",
|
|
256
|
+
"severity": "medium",
|
|
257
|
+
"title": "insertAdjacentHTML usage",
|
|
258
|
+
"description": "insertAdjacentHTML can lead to XSS if the inserted content is not sanitized.",
|
|
259
|
+
"matcher": {
|
|
260
|
+
"type": "regex",
|
|
261
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
262
|
+
"pattern": "\\binsertAdjacentHTML\\s*\\(",
|
|
263
|
+
"message": "insertAdjacentHTML detected; ensure content is sanitized"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": "nextjs/document-write",
|
|
268
|
+
"severity": "medium",
|
|
269
|
+
"title": "document.write usage",
|
|
270
|
+
"description": "document.write can enable XSS and should generally be avoided.",
|
|
271
|
+
"matcher": {
|
|
272
|
+
"type": "regex",
|
|
273
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
274
|
+
"pattern": "document\\.write\\s*\\(",
|
|
275
|
+
"message": "document.write detected; avoid raw HTML injection"
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "nextjs/document-writeln",
|
|
280
|
+
"severity": "medium",
|
|
281
|
+
"title": "document.writeln usage",
|
|
282
|
+
"description": "document.writeln can enable XSS and should generally be avoided.",
|
|
283
|
+
"matcher": {
|
|
284
|
+
"type": "regex",
|
|
285
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
286
|
+
"pattern": "document\\.writeln\\s*\\(",
|
|
287
|
+
"message": "document.writeln detected; avoid raw HTML injection"
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "nextjs/csp-unsafe-inline",
|
|
292
|
+
"severity": "high",
|
|
293
|
+
"title": "CSP allows unsafe-inline",
|
|
294
|
+
"description": "CSP with unsafe-inline weakens script protections and increases XSS risk.",
|
|
295
|
+
"matcher": {
|
|
296
|
+
"type": "regex",
|
|
297
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
298
|
+
"pattern": "Content-Security-Policy[^\\n\\r]*unsafe-inline",
|
|
299
|
+
"message": "Content-Security-Policy includes unsafe-inline"
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"id": "nextjs/csp-unsafe-eval",
|
|
304
|
+
"severity": "high",
|
|
305
|
+
"title": "CSP allows unsafe-eval",
|
|
306
|
+
"description": "CSP with unsafe-eval weakens script protections and increases XSS risk.",
|
|
307
|
+
"matcher": {
|
|
308
|
+
"type": "regex",
|
|
309
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
310
|
+
"pattern": "Content-Security-Policy[^\\n\\r]*unsafe-eval",
|
|
311
|
+
"message": "Content-Security-Policy includes unsafe-eval"
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"id": "nextjs/postmessage-wildcard-origin",
|
|
316
|
+
"severity": "medium",
|
|
317
|
+
"title": "postMessage to wildcard origin",
|
|
318
|
+
"description": "Using postMessage with targetOrigin '*' can leak data to unexpected receivers.",
|
|
319
|
+
"matcher": {
|
|
320
|
+
"type": "regex",
|
|
321
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
322
|
+
"pattern": "postMessage\\s*\\([^\\)]*,\\s*['\"]\\*['\"]",
|
|
323
|
+
"message": "postMessage targetOrigin appears to be '*'"
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"id": "nextjs/eval",
|
|
328
|
+
"severity": "high",
|
|
329
|
+
"title": "eval usage",
|
|
330
|
+
"description": "eval can enable code injection vulnerabilities and is strongly discouraged.",
|
|
331
|
+
"matcher": {
|
|
332
|
+
"type": "regex",
|
|
333
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
334
|
+
"pattern": "\\beval\\s*\\(",
|
|
335
|
+
"message": "eval detected; avoid dynamic code execution"
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"id": "nextjs/new-function",
|
|
340
|
+
"severity": "high",
|
|
341
|
+
"title": "Function constructor usage",
|
|
342
|
+
"description": "new Function can enable code injection vulnerabilities and is strongly discouraged.",
|
|
343
|
+
"matcher": {
|
|
344
|
+
"type": "regex",
|
|
345
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
346
|
+
"pattern": "\\bnew\\s+Function\\s*\\(",
|
|
347
|
+
"message": "new Function detected; avoid dynamic code execution"
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"id": "nextjs/settimeout-string",
|
|
352
|
+
"severity": "medium",
|
|
353
|
+
"title": "setTimeout called with a string",
|
|
354
|
+
"description": "setTimeout with a string behaves like eval and can enable injection vulnerabilities.",
|
|
355
|
+
"matcher": {
|
|
356
|
+
"type": "regex",
|
|
357
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
358
|
+
"pattern": "\\bsetTimeout\\s*\\(\\s*['\"]",
|
|
359
|
+
"message": "setTimeout appears to be called with a string"
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"id": "nextjs/setinterval-string",
|
|
364
|
+
"severity": "medium",
|
|
365
|
+
"title": "setInterval called with a string",
|
|
366
|
+
"description": "setInterval with a string behaves like eval and can enable injection vulnerabilities.",
|
|
367
|
+
"matcher": {
|
|
368
|
+
"type": "regex",
|
|
369
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
370
|
+
"pattern": "\\bsetInterval\\s*\\(\\s*['\"]",
|
|
371
|
+
"message": "setInterval appears to be called with a string"
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"id": "nextjs/node-tls-reject-unauthorized-zero",
|
|
376
|
+
"severity": "high",
|
|
377
|
+
"title": "TLS verification disabled",
|
|
378
|
+
"description": "Setting NODE_TLS_REJECT_UNAUTHORIZED=0 disables TLS verification and enables MITM attacks.",
|
|
379
|
+
"matcher": {
|
|
380
|
+
"type": "regex",
|
|
381
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
382
|
+
"pattern": "NODE_TLS_REJECT_UNAUTHORIZED[^=]{0,20}=\\s*['\"]0['\"]",
|
|
383
|
+
"message": "NODE_TLS_REJECT_UNAUTHORIZED is set to 0"
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"id": "nextjs/https-agent-reject-unauthorized-false",
|
|
388
|
+
"severity": "high",
|
|
389
|
+
"title": "HTTPS agent with rejectUnauthorized: false",
|
|
390
|
+
"description": "Disabling TLS verification enables man-in-the-middle attacks.",
|
|
391
|
+
"matcher": {
|
|
392
|
+
"type": "regex",
|
|
393
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
394
|
+
"pattern": "rejectUnauthorized\\s*:\\s*false",
|
|
395
|
+
"message": "rejectUnauthorized appears to be false"
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"id": "nextjs/fetch-http-url",
|
|
400
|
+
"severity": "medium",
|
|
401
|
+
"title": "fetch to plain HTTP URL",
|
|
402
|
+
"description": "Making requests over HTTP can expose sensitive data to interception.",
|
|
403
|
+
"matcher": {
|
|
404
|
+
"type": "regex",
|
|
405
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
406
|
+
"pattern": "\\bfetch\\s*\\(\\s*['\"]http://",
|
|
407
|
+
"message": "fetch appears to target an http:// URL"
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"id": "nextjs/axios-http-url",
|
|
412
|
+
"severity": "medium",
|
|
413
|
+
"title": "axios to plain HTTP URL",
|
|
414
|
+
"description": "Making requests over HTTP can expose sensitive data to interception.",
|
|
415
|
+
"matcher": {
|
|
416
|
+
"type": "regex",
|
|
417
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
418
|
+
"pattern": "\\baxios\\.(get|post|put|patch|delete|request)\\s*\\(\\s*['\"]http://",
|
|
419
|
+
"message": "axios appears to target an http:// URL"
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"id": "nextjs/child-process-exec",
|
|
424
|
+
"severity": "high",
|
|
425
|
+
"title": "child_process exec usage",
|
|
426
|
+
"description": "Executing shell commands can lead to command injection vulnerabilities.",
|
|
427
|
+
"matcher": {
|
|
428
|
+
"type": "regex",
|
|
429
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
430
|
+
"pattern": "\\bexec\\s*\\(",
|
|
431
|
+
"message": "exec detected; ensure inputs are not user-controlled"
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"id": "nextjs/child-process-execsync",
|
|
436
|
+
"severity": "high",
|
|
437
|
+
"title": "child_process execSync usage",
|
|
438
|
+
"description": "Executing shell commands can lead to command injection vulnerabilities.",
|
|
439
|
+
"matcher": {
|
|
440
|
+
"type": "regex",
|
|
441
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
442
|
+
"pattern": "\\bexecSync\\s*\\(",
|
|
443
|
+
"message": "execSync detected; ensure inputs are not user-controlled"
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"id": "nextjs/child-process-spawn",
|
|
448
|
+
"severity": "high",
|
|
449
|
+
"title": "child_process spawn usage",
|
|
450
|
+
"description": "Spawning subprocesses can lead to command injection vulnerabilities.",
|
|
451
|
+
"matcher": {
|
|
452
|
+
"type": "regex",
|
|
453
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
454
|
+
"pattern": "\\bspawn\\s*\\(",
|
|
455
|
+
"message": "spawn detected; ensure inputs are not user-controlled"
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"id": "nextjs/child-process-spawnsync",
|
|
460
|
+
"severity": "high",
|
|
461
|
+
"title": "child_process spawnSync usage",
|
|
462
|
+
"description": "Spawning subprocesses can lead to command injection vulnerabilities.",
|
|
463
|
+
"matcher": {
|
|
464
|
+
"type": "regex",
|
|
465
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
466
|
+
"pattern": "\\bspawnSync\\s*\\(",
|
|
467
|
+
"message": "spawnSync detected; ensure inputs are not user-controlled"
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"id": "nextjs/child-process-fork",
|
|
472
|
+
"severity": "medium",
|
|
473
|
+
"title": "child_process fork usage",
|
|
474
|
+
"description": "Forking subprocesses can increase attack surface; ensure the child module path is safe.",
|
|
475
|
+
"matcher": {
|
|
476
|
+
"type": "regex",
|
|
477
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
478
|
+
"pattern": "\\bfork\\s*\\(",
|
|
479
|
+
"message": "fork detected; ensure the child module path is safe"
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"id": "nextjs/crypto-md5",
|
|
484
|
+
"severity": "medium",
|
|
485
|
+
"title": "MD5 hashing",
|
|
486
|
+
"description": "MD5 is considered cryptographically broken and unsuitable for security-sensitive use.",
|
|
487
|
+
"matcher": {
|
|
488
|
+
"type": "regex",
|
|
489
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
490
|
+
"pattern": "createHash\\s*\\(\\s*['\"]md5['\"]",
|
|
491
|
+
"message": "MD5 hashing detected; avoid for security-sensitive use"
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"id": "nextjs/crypto-sha1",
|
|
496
|
+
"severity": "low",
|
|
497
|
+
"title": "SHA-1 hashing",
|
|
498
|
+
"description": "SHA-1 is considered weak for collision resistance and should be avoided for new security-sensitive uses.",
|
|
499
|
+
"matcher": {
|
|
500
|
+
"type": "regex",
|
|
501
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
502
|
+
"pattern": "createHash\\s*\\(\\s*['\"]sha1['\"]",
|
|
503
|
+
"message": "SHA-1 hashing detected; avoid for security-sensitive use"
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"id": "nextjs/math-random",
|
|
508
|
+
"severity": "medium",
|
|
509
|
+
"title": "Math.random usage",
|
|
510
|
+
"description": "Math.random is not cryptographically secure and should not be used for secrets or tokens.",
|
|
511
|
+
"matcher": {
|
|
512
|
+
"type": "regex",
|
|
513
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
514
|
+
"pattern": "Math\\.random\\s*\\(",
|
|
515
|
+
"message": "Math.random detected; avoid for security-sensitive use"
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"id": "nextjs/console-log-env",
|
|
520
|
+
"severity": "medium",
|
|
521
|
+
"title": "Logging environment variables",
|
|
522
|
+
"description": "Logging process.env can leak secrets into logs.",
|
|
523
|
+
"matcher": {
|
|
524
|
+
"type": "regex",
|
|
525
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
526
|
+
"pattern": "console\\.(log|info|debug|warn|error)\\s*\\([^\\)]*process\\.env",
|
|
527
|
+
"message": "process.env appears in console output"
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
"id": "nextjs/localstorage-sensitive-key",
|
|
532
|
+
"severity": "high",
|
|
533
|
+
"title": "Potential secret stored in localStorage",
|
|
534
|
+
"description": "localStorage is not suitable for storing secrets; prefer HttpOnly cookies or secure storage patterns.",
|
|
535
|
+
"matcher": {
|
|
536
|
+
"type": "regex",
|
|
537
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
538
|
+
"pattern": "localStorage\\.setItem\\(\\s*['\\\"][^'\\\"]*(token|secret|key|password)[^'\\\"]*['\\\"]",
|
|
539
|
+
"message": "localStorage key name suggests sensitive data storage"
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"id": "nextjs/sessionstorage-sensitive-key",
|
|
544
|
+
"severity": "high",
|
|
545
|
+
"title": "Potential secret stored in sessionStorage",
|
|
546
|
+
"description": "sessionStorage is not suitable for storing secrets; prefer HttpOnly cookies or secure storage patterns.",
|
|
547
|
+
"matcher": {
|
|
548
|
+
"type": "regex",
|
|
549
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
550
|
+
"pattern": "sessionStorage\\.setItem\\(\\s*['\\\"][^'\\\"]*(token|secret|key|password)[^'\\\"]*['\\\"]",
|
|
551
|
+
"message": "sessionStorage key name suggests sensitive data storage"
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"id": "nextjs/document-cookie-assignment",
|
|
556
|
+
"severity": "medium",
|
|
557
|
+
"title": "document.cookie assignment",
|
|
558
|
+
"description": "Setting cookies via document.cookie increases the risk of exposing session tokens to XSS.",
|
|
559
|
+
"matcher": {
|
|
560
|
+
"type": "regex",
|
|
561
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
562
|
+
"pattern": "document\\.cookie\\s*=",
|
|
563
|
+
"message": "document.cookie assignment detected"
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
"id": "nextjs/cookie-secure-false",
|
|
568
|
+
"severity": "high",
|
|
569
|
+
"title": "Cookie secure flag disabled",
|
|
570
|
+
"description": "Cookies without secure flag can be sent over HTTP.",
|
|
571
|
+
"matcher": {
|
|
572
|
+
"type": "regex",
|
|
573
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
574
|
+
"pattern": "\\bsecure\\s*:\\s*false",
|
|
575
|
+
"message": "secure: false detected on a cookie-like object"
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"id": "nextjs/cookie-httponly-false",
|
|
580
|
+
"severity": "high",
|
|
581
|
+
"title": "Cookie httpOnly flag disabled",
|
|
582
|
+
"description": "Cookies without httpOnly can be accessed by JavaScript and stolen via XSS.",
|
|
583
|
+
"matcher": {
|
|
584
|
+
"type": "regex",
|
|
585
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
586
|
+
"pattern": "\\bhttpOnly\\s*:\\s*false",
|
|
587
|
+
"message": "httpOnly: false detected on a cookie-like object"
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"id": "nextjs/cookie-samesite-none",
|
|
592
|
+
"severity": "medium",
|
|
593
|
+
"title": "Cookie SameSite set to none",
|
|
594
|
+
"description": "SameSite=none can enable cross-site cookie sending; ensure secure and CSRF protections.",
|
|
595
|
+
"matcher": {
|
|
596
|
+
"type": "regex",
|
|
597
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
598
|
+
"pattern": "sameSite\\s*:\\s*['\"]none['\"]",
|
|
599
|
+
"message": "sameSite appears to be set to 'none'"
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"id": "nextjs/cookie-domain-dot",
|
|
604
|
+
"severity": "medium",
|
|
605
|
+
"title": "Cookie domain set to a dot-prefixed domain",
|
|
606
|
+
"description": "Setting a cookie for a wide domain can increase exposure across subdomains.",
|
|
607
|
+
"matcher": {
|
|
608
|
+
"type": "regex",
|
|
609
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
610
|
+
"pattern": "domain\\s*:\\s*['\"]\\.[^'\"]+['\"]",
|
|
611
|
+
"message": "Cookie domain appears to be set for all subdomains"
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"id": "nextjs/cors-origin-wildcard",
|
|
616
|
+
"severity": "high",
|
|
617
|
+
"title": "CORS origin '*' configured",
|
|
618
|
+
"description": "Allowing origin '*' can expose endpoints to cross-origin callers.",
|
|
619
|
+
"matcher": {
|
|
620
|
+
"type": "regex",
|
|
621
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
622
|
+
"pattern": "\\borigin\\s*:\\s*['\"]\\*['\"]",
|
|
623
|
+
"message": "CORS origin appears to be configured as '*'"
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
"id": "nextjs/header-location-from-user-input",
|
|
628
|
+
"severity": "high",
|
|
629
|
+
"title": "Location header from user input",
|
|
630
|
+
"description": "Setting Location from user-controlled input can enable open redirects and header injection.",
|
|
631
|
+
"matcher": {
|
|
632
|
+
"type": "regex",
|
|
633
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
634
|
+
"pattern": "setHeader\\s*\\(\\s*['\"]Location['\"][^\\)]*(req\\.query|searchParams\\.get)",
|
|
635
|
+
"message": "Location header appears to use user-controlled input"
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
"id": "nextjs/redirect-from-user-input",
|
|
640
|
+
"severity": "high",
|
|
641
|
+
"title": "Redirect destination from user input",
|
|
642
|
+
"description": "Redirecting to user-controlled URLs can enable open redirects.",
|
|
643
|
+
"matcher": {
|
|
644
|
+
"type": "regex",
|
|
645
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
646
|
+
"pattern": "\\bredirect\\s*\\([^\\)]*(searchParams\\.get|req\\.query|nextUrl\\.searchParams\\.get)",
|
|
647
|
+
"message": "redirect appears to use user-controlled input"
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"id": "nextjs/nextauth-debug-enabled",
|
|
652
|
+
"severity": "medium",
|
|
653
|
+
"title": "NextAuth debug enabled",
|
|
654
|
+
"description": "Enabling debug logs can leak sensitive information.",
|
|
655
|
+
"matcher": {
|
|
656
|
+
"type": "regex",
|
|
657
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
658
|
+
"pattern": "\\bdebug\\s*:\\s*true",
|
|
659
|
+
"message": "debug appears to be enabled"
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"id": "nextjs/yaml-load",
|
|
664
|
+
"severity": "medium",
|
|
665
|
+
"title": "YAML load/parse usage",
|
|
666
|
+
"description": "Parsing YAML from untrusted input can be risky depending on the parser configuration.",
|
|
667
|
+
"matcher": {
|
|
668
|
+
"type": "regex",
|
|
669
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
670
|
+
"pattern": "\\byaml\\.(load|safeLoad)\\s*\\(",
|
|
671
|
+
"message": "YAML load/parse detected; ensure input is trusted"
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"id": "nextjs/vm-runinthiscontext",
|
|
676
|
+
"severity": "high",
|
|
677
|
+
"title": "vm.runInThisContext usage",
|
|
678
|
+
"description": "Running arbitrary code via Node vm can enable code execution vulnerabilities.",
|
|
679
|
+
"matcher": {
|
|
680
|
+
"type": "regex",
|
|
681
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
682
|
+
"pattern": "\\bvm\\.runInThisContext\\s*\\(",
|
|
683
|
+
"message": "vm.runInThisContext detected; avoid dynamic code execution"
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
"id": "nextjs/vm-script",
|
|
688
|
+
"severity": "high",
|
|
689
|
+
"title": "vm.Script usage",
|
|
690
|
+
"description": "Compiling code via Node vm can enable code execution vulnerabilities.",
|
|
691
|
+
"matcher": {
|
|
692
|
+
"type": "regex",
|
|
693
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
694
|
+
"pattern": "\\bnew\\s+vm\\.Script\\s*\\(",
|
|
695
|
+
"message": "new vm.Script detected; avoid dynamic code execution"
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
"id": "nextjs/deserialize-unsafe-json",
|
|
700
|
+
"severity": "medium",
|
|
701
|
+
"title": "JSON.parse on request body",
|
|
702
|
+
"description": "Blindly parsing request bodies can be risky; ensure schema validation and size limits.",
|
|
703
|
+
"matcher": {
|
|
704
|
+
"type": "regex",
|
|
705
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
706
|
+
"pattern": "JSON\\.parse\\s*\\(\\s*req\\.body",
|
|
707
|
+
"message": "JSON.parse(req.body) detected; ensure validation and limits"
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
"id": "nextjs/new-regexp-user-input",
|
|
712
|
+
"severity": "medium",
|
|
713
|
+
"title": "RegExp from dynamic input",
|
|
714
|
+
"description": "Constructing regular expressions from untrusted input can lead to ReDoS or unintended matches.",
|
|
715
|
+
"matcher": {
|
|
716
|
+
"type": "regex",
|
|
717
|
+
"fileGlobs": ["**/*.{js,jsx,ts,tsx}"],
|
|
718
|
+
"pattern": "new\\s+RegExp\\s*\\([^\\)]*(userInput|req\\.query|searchParams\\.get)",
|
|
719
|
+
"message": "new RegExp appears to use dynamic input"
|
|
720
|
+
}
|
|
37
721
|
}
|
|
38
722
|
]
|