xploitscan-shared-rules 1.13.0 → 1.13.1
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/index.cjs +163 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +163 -81
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,13 +1,48 @@
|
|
|
1
1
|
// src/snippet.ts
|
|
2
|
-
|
|
2
|
+
var cacheContent = null;
|
|
3
|
+
var cacheLines = [];
|
|
4
|
+
var cacheOffsets = [];
|
|
5
|
+
function lineIndex(content) {
|
|
6
|
+
if (content === cacheContent) return { lines: cacheLines, offsets: cacheOffsets };
|
|
3
7
|
const lines = content.split("\n");
|
|
8
|
+
const offsets = new Array(lines.length);
|
|
9
|
+
let off = 0;
|
|
10
|
+
for (let i = 0; i < lines.length; i++) {
|
|
11
|
+
offsets[i] = off;
|
|
12
|
+
off += lines[i].length + 1;
|
|
13
|
+
}
|
|
14
|
+
cacheContent = content;
|
|
15
|
+
cacheLines = lines;
|
|
16
|
+
cacheOffsets = offsets;
|
|
17
|
+
return { lines, offsets };
|
|
18
|
+
}
|
|
19
|
+
function lineNumberAt(content, index) {
|
|
20
|
+
const { offsets } = lineIndex(content);
|
|
21
|
+
let lo = 0;
|
|
22
|
+
let hi = offsets.length - 1;
|
|
23
|
+
let ans = 0;
|
|
24
|
+
while (lo <= hi) {
|
|
25
|
+
const mid = lo + hi >> 1;
|
|
26
|
+
if (offsets[mid] <= index) {
|
|
27
|
+
ans = mid;
|
|
28
|
+
lo = mid + 1;
|
|
29
|
+
} else {
|
|
30
|
+
hi = mid - 1;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return ans + 1;
|
|
34
|
+
}
|
|
35
|
+
function getSnippet(content, line, contextLines = 2) {
|
|
36
|
+
const { lines } = lineIndex(content);
|
|
4
37
|
const start = Math.max(0, line - 1 - contextLines);
|
|
5
38
|
const end = Math.min(lines.length, line + contextLines);
|
|
6
|
-
|
|
7
|
-
|
|
39
|
+
const out = [];
|
|
40
|
+
for (let i = start; i < end; i++) {
|
|
41
|
+
const lineNum = i + 1;
|
|
8
42
|
const marker = lineNum === line ? ">" : " ";
|
|
9
|
-
|
|
10
|
-
}
|
|
43
|
+
out.push(`${marker} ${lineNum.toString().padStart(4)} | ${lines[i]}`);
|
|
44
|
+
}
|
|
45
|
+
return out.join("\n");
|
|
11
46
|
}
|
|
12
47
|
|
|
13
48
|
// src/rule-impacts.ts
|
|
@@ -815,7 +850,7 @@ var SERVER_SIDE_PATH_RE = new RegExp(
|
|
|
815
850
|
].join("|"),
|
|
816
851
|
"i"
|
|
817
852
|
);
|
|
818
|
-
var SERVER_SIDE_CONTENT_RE = /\b(?:req|request)\.(?:body|query|params|headers|cookies)\b|\b(?:app|router)\.(?:get|post|put|patch|delete|use|all)\s*\(|\bctx\.request\b|\bevent\.(?:body|queryStringParameters|pathParameters)\b|\(\s*req\s*,\s*res\b|(?:import|require)\b[^;\n]
|
|
853
|
+
var SERVER_SIDE_CONTENT_RE = /\b(?:req|request)\.(?:body|query|params|headers|cookies)\b|\b(?:app|router)\.(?:get|post|put|patch|delete|use|all)\s*\(|\bctx\.request\b|\bevent\.(?:body|queryStringParameters|pathParameters)\b|\(\s*req\s*,\s*res\b|(?:import|require)\b[^;\n]{0,200}['"]express['"]|\bNextFunction\b/;
|
|
819
854
|
function isServerSideFile(filePath, content) {
|
|
820
855
|
if (isTestFile(filePath)) return false;
|
|
821
856
|
if (SERVER_SIDE_PATH_RE.test(filePath)) return true;
|
|
@@ -862,13 +897,23 @@ function filterSilenced(matches, content, ruleId) {
|
|
|
862
897
|
}
|
|
863
898
|
function findMatches(content, pattern, rule, filePath, fixTemplate) {
|
|
864
899
|
const matches = [];
|
|
865
|
-
const lines = content.split("\n");
|
|
866
900
|
let m;
|
|
867
901
|
const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
|
|
902
|
+
let scanned = 0;
|
|
903
|
+
let lineNum = 1;
|
|
904
|
+
let lastMatchIndex = -1;
|
|
905
|
+
const MAX_MATCHES = 500;
|
|
868
906
|
while ((m = re.exec(content)) !== null) {
|
|
907
|
+
if (m.index === lastMatchIndex && m[0].length === 0) {
|
|
908
|
+
re.lastIndex++;
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
lastMatchIndex = m.index;
|
|
869
912
|
if (isCommentLine(content, m.index)) continue;
|
|
870
913
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
871
|
-
|
|
914
|
+
for (; scanned < m.index; scanned++) {
|
|
915
|
+
if (content.charCodeAt(scanned) === 10) lineNum++;
|
|
916
|
+
}
|
|
872
917
|
matches.push({
|
|
873
918
|
rule: rule.id,
|
|
874
919
|
title: rule.title,
|
|
@@ -879,6 +924,7 @@ function findMatches(content, pattern, rule, filePath, fixTemplate) {
|
|
|
879
924
|
snippet: getSnippet(content, lineNum),
|
|
880
925
|
fix: fixTemplate?.(m)
|
|
881
926
|
});
|
|
927
|
+
if (matches.length >= MAX_MATCHES) break;
|
|
882
928
|
}
|
|
883
929
|
return matches;
|
|
884
930
|
}
|
|
@@ -894,10 +940,26 @@ function astMatch(content, filePath, line, rule, fix) {
|
|
|
894
940
|
fix
|
|
895
941
|
};
|
|
896
942
|
}
|
|
943
|
+
var parseCacheContent = null;
|
|
944
|
+
var parseCachePath = null;
|
|
945
|
+
var parseCacheResult = null;
|
|
946
|
+
var parseCacheValid = false;
|
|
897
947
|
function tryParse(content, filePath) {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
948
|
+
if (parseCacheValid && content === parseCacheContent && filePath === parseCachePath) {
|
|
949
|
+
return parseCacheResult;
|
|
950
|
+
}
|
|
951
|
+
let result = null;
|
|
952
|
+
try {
|
|
953
|
+
const parsed = parseFile(content, filePath);
|
|
954
|
+
result = parsed ? { parsed, taint: buildTaintMap(parsed) } : null;
|
|
955
|
+
} catch {
|
|
956
|
+
result = null;
|
|
957
|
+
}
|
|
958
|
+
parseCacheResult = result;
|
|
959
|
+
parseCacheContent = content;
|
|
960
|
+
parseCachePath = filePath;
|
|
961
|
+
parseCacheValid = true;
|
|
962
|
+
return result;
|
|
901
963
|
}
|
|
902
964
|
var hardcodedSecrets = {
|
|
903
965
|
id: "VC001",
|
|
@@ -1265,7 +1327,7 @@ var xssVulnerability = {
|
|
|
1265
1327
|
const hasSanitizerBypass = /bypassSecurityTrust(?:Html|Script|Style|Url|ResourceUrl)\s*\(/.test(content);
|
|
1266
1328
|
if (/(?:sanitize|purify|escape|xss)/i.test(filePath)) return [];
|
|
1267
1329
|
if (!hasSanitizerBypass && /DOMPurify\.sanitize|sanitizeHtml|xss\(|escapeHtml/i.test(content)) return [];
|
|
1268
|
-
if (!hasSanitizerBypass && /(?:import|require)\s*\(
|
|
1330
|
+
if (!hasSanitizerBypass && /(?:import|require)\s*\(?[^\n]{0,200}(?:DOMPurify|dompurify|sanitize|sanitizer)/i.test(content)) return [];
|
|
1269
1331
|
const patterns = [
|
|
1270
1332
|
// React dangerouslySetInnerHTML
|
|
1271
1333
|
/dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:/g,
|
|
@@ -1294,9 +1356,9 @@ var xssVulnerability = {
|
|
|
1294
1356
|
() => "Sanitize user input before rendering as HTML. Use a library like DOMPurify: DOMPurify.sanitize(userInput). If this site is intentional (JSON-LD structured data, a const boot script, a sandboxed preview), add an inline `// VC007-OK: <reason>` comment above the line to silence."
|
|
1295
1357
|
);
|
|
1296
1358
|
for (const m of raw) {
|
|
1297
|
-
const lineText = allLines[m.line - 1] || "";
|
|
1359
|
+
const lineText = (allLines[m.line - 1] || "").slice(0, 4e3);
|
|
1298
1360
|
if (/\.innerHTML\s*=\s*['"]/.test(lineText) && !/\$\{/.test(lineText)) continue;
|
|
1299
|
-
if (/\.innerHTML\s*=\s*['"][^'"]
|
|
1361
|
+
if (/\.innerHTML\s*=\s*['"][^'"]{0,2000}['"]\s*$/.test(lineText)) continue;
|
|
1300
1362
|
if (/dangerouslySetInnerHTML/.test(lineText)) {
|
|
1301
1363
|
const windowText = allLines.slice(m.line - 1, m.line + 2).join("\n");
|
|
1302
1364
|
if (/JSON\.stringify/i.test(windowText)) continue;
|
|
@@ -1547,7 +1609,7 @@ var evalUsage = {
|
|
|
1547
1609
|
/new\s+Function\s*\(\s*(?!["'`])/g
|
|
1548
1610
|
];
|
|
1549
1611
|
const hasEvalInString = /["'`]eval(?:-source-map|["'`])/i.test(content);
|
|
1550
|
-
if (hasEvalInString && !/\beval\s*\([^)]
|
|
1612
|
+
if (hasEvalInString && !/\beval\s*\([^)]{0,500}(?:req\.|body\.|input|params|user|data)/i.test(content)) return [];
|
|
1551
1613
|
const matches = [];
|
|
1552
1614
|
for (const p of patterns) {
|
|
1553
1615
|
const rawMatches = findMatches(
|
|
@@ -1588,7 +1650,7 @@ var unvalidatedRedirect = {
|
|
|
1588
1650
|
const isPureLiteral = /^["'`][^"'`]*["'`]$/.test(value);
|
|
1589
1651
|
if (!hasInterpolation && isPureLiteral) continue;
|
|
1590
1652
|
if (isInlineSilenced(content, m.index, "VC016")) continue;
|
|
1591
|
-
const line = content
|
|
1653
|
+
const line = lineNumberAt(content, m.index);
|
|
1592
1654
|
matches.push({
|
|
1593
1655
|
rule: "VC016",
|
|
1594
1656
|
title: unvalidatedRedirect.title,
|
|
@@ -1811,11 +1873,11 @@ var prototypePollution = {
|
|
|
1811
1873
|
];
|
|
1812
1874
|
const hasValidation = /schema|validate|sanitize|whitelist|allowedKeys|pick\(|Object\.freeze|zod|yup|joi|ajv/i.test(content);
|
|
1813
1875
|
if (!hasValidation) {
|
|
1814
|
-
const hasUnsafeMerge = /Object\.assign\s*\([^)]
|
|
1876
|
+
const hasUnsafeMerge = /Object\.assign\s*\([^)]{0,500}JSON\.parse|\.\.\.JSON\.parse|\{[^\n]{0,300}\.\.\.(?:stored|saved|cached|parsed|data)/i.test(content);
|
|
1815
1877
|
if (hasUnsafeMerge) {
|
|
1816
1878
|
matches.push(...findMatches(
|
|
1817
1879
|
content,
|
|
1818
|
-
/Object\.assign\s*\([^)]
|
|
1880
|
+
/Object\.assign\s*\([^)]{0,500}JSON\.parse|\.\.\.JSON\.parse/g,
|
|
1819
1881
|
prototypePollution,
|
|
1820
1882
|
filePath,
|
|
1821
1883
|
() => "Validate parsed data against an expected schema before merging into objects. Use Object.freeze(), a validation library (Zod, Yup), or manually check for __proto__ and constructor keys."
|
|
@@ -3361,7 +3423,7 @@ var dangerousInnerHTML = {
|
|
|
3361
3423
|
if (/^[A-Z][A-Z0-9_]+$/.test(value)) continue;
|
|
3362
3424
|
if (/^["'`][^$]*["'`]$/.test(value)) continue;
|
|
3363
3425
|
if (/JSON\.stringify/i.test(value)) continue;
|
|
3364
|
-
const lineNum = content
|
|
3426
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
3365
3427
|
findings.push({
|
|
3366
3428
|
rule: "VC063",
|
|
3367
3429
|
title: dangerousInnerHTML.title,
|
|
@@ -4103,7 +4165,7 @@ var missingSRI = {
|
|
|
4103
4165
|
const re = new RegExp(scriptPattern.source, scriptPattern.flags);
|
|
4104
4166
|
while ((m = re.exec(content)) !== null) {
|
|
4105
4167
|
if (!m[0].includes("integrity")) {
|
|
4106
|
-
const lineNum = content
|
|
4168
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
4107
4169
|
matches.push({
|
|
4108
4170
|
rule: "VC084",
|
|
4109
4171
|
title: missingSRI.title,
|
|
@@ -4974,7 +5036,7 @@ var s3BucketNoEncryption = {
|
|
|
4974
5036
|
const blockEnd = Math.min(m.index + 2e3, content.length);
|
|
4975
5037
|
const blockContent = content.substring(m.index, blockEnd);
|
|
4976
5038
|
if (!/server_side_encryption/.test(blockContent)) {
|
|
4977
|
-
const lineNum = content
|
|
5039
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
4978
5040
|
matches.push({
|
|
4979
5041
|
rule: "VC107",
|
|
4980
5042
|
title: s3BucketNoEncryption.title,
|
|
@@ -5005,7 +5067,7 @@ var securityGroupAllInbound = {
|
|
|
5005
5067
|
while ((m = ingressPattern.exec(content)) !== null) {
|
|
5006
5068
|
if (isCommentLine(content, m.index)) continue;
|
|
5007
5069
|
if (/from_port\s*=\s*0/.test(m[0]) || !/from_port/.test(m[0])) {
|
|
5008
|
-
const lineNum = content
|
|
5070
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5009
5071
|
matches.push({
|
|
5010
5072
|
rule: "VC108",
|
|
5011
5073
|
title: securityGroupAllInbound.title,
|
|
@@ -5092,7 +5154,7 @@ var lambdaWithoutVPC = {
|
|
|
5092
5154
|
const blockEnd = Math.min(m.index + 2e3, content.length);
|
|
5093
5155
|
const blockContent = content.substring(m.index, blockEnd);
|
|
5094
5156
|
if (!/vpc_config\s*\{/.test(blockContent)) {
|
|
5095
|
-
const lineNum = content
|
|
5157
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5096
5158
|
matches.push({
|
|
5097
5159
|
rule: "VC111",
|
|
5098
5160
|
title: lambdaWithoutVPC.title,
|
|
@@ -5122,7 +5184,7 @@ var dockerLatestTag = {
|
|
|
5122
5184
|
while ((m = fromPattern.exec(content)) !== null) {
|
|
5123
5185
|
const image = m[1];
|
|
5124
5186
|
if (image.endsWith(":latest") || !image.includes(":") && !image.startsWith("$")) {
|
|
5125
|
-
const lineNum = content
|
|
5187
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5126
5188
|
matches.push({
|
|
5127
5189
|
rule: "VC112",
|
|
5128
5190
|
title: dockerLatestTag.title,
|
|
@@ -5250,17 +5312,26 @@ var pathTraversal = {
|
|
|
5250
5312
|
const findings = [];
|
|
5251
5313
|
const patterns = [
|
|
5252
5314
|
/(?:readFile|readFileSync|createReadStream|writeFile|writeFileSync|appendFile|unlink|unlinkSync|access|stat|statSync|existsSync)\s*\(\s*(?:req\.|request\.|ctx\.|params\.|query\.)/gi,
|
|
5253
|
-
/(?:path\.join|path\.resolve)\s*\([^)]
|
|
5254
|
-
/(?:res\.sendFile|res\.download)\s*\([^)]
|
|
5315
|
+
/(?:path\.join|path\.resolve)\s*\([^)]{0,500}(?:req\.|request\.|ctx\.|params\.|query\.)[^)]{0,500}\)/gi,
|
|
5316
|
+
/(?:res\.sendFile|res\.download)\s*\([^)]{0,500}(?:req\.|request\.)/gi,
|
|
5255
5317
|
/open\s*\(\s*(?:request\.|params\[|args\.)/gi
|
|
5256
5318
|
];
|
|
5319
|
+
const MAX_MATCHES = 500;
|
|
5257
5320
|
for (const pat of patterns) {
|
|
5321
|
+
if (findings.length >= MAX_MATCHES) break;
|
|
5258
5322
|
let m;
|
|
5323
|
+
let lastIdx = -1;
|
|
5259
5324
|
while ((m = pat.exec(content)) !== null) {
|
|
5325
|
+
if (findings.length >= MAX_MATCHES) break;
|
|
5326
|
+
if (m.index === lastIdx && m[0].length === 0) {
|
|
5327
|
+
pat.lastIndex++;
|
|
5328
|
+
continue;
|
|
5329
|
+
}
|
|
5330
|
+
lastIdx = m.index;
|
|
5260
5331
|
if (isCommentLine(content, m.index)) continue;
|
|
5261
5332
|
const surrounding = content.substring(Math.max(0, m.index - 200), m.index + 200);
|
|
5262
5333
|
if (/path\.normalize|sanitize|\.replace\(\s*['"]\.\.|\.startsWith\s*\(|realpath/i.test(surrounding)) continue;
|
|
5263
|
-
const lineNum = content
|
|
5334
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5264
5335
|
findings.push({
|
|
5265
5336
|
rule: "VC117",
|
|
5266
5337
|
title: pathTraversal.title,
|
|
@@ -5291,7 +5362,7 @@ var piiInLogs = {
|
|
|
5291
5362
|
while ((m = logPattern.exec(content)) !== null) {
|
|
5292
5363
|
if (isCommentLine(content, m.index)) continue;
|
|
5293
5364
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
5294
|
-
const lineNum = content
|
|
5365
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5295
5366
|
findings.push({
|
|
5296
5367
|
rule: "VC118",
|
|
5297
5368
|
title: piiInLogs.title,
|
|
@@ -5329,7 +5400,7 @@ var hardcodedOAuthSecret = {
|
|
|
5329
5400
|
while ((m = pat.exec(content)) !== null) {
|
|
5330
5401
|
if (isCommentLine(content, m.index)) continue;
|
|
5331
5402
|
if (/process\.env|os\.environ|ENV\[|getenv|\$\{|<your|CHANGE_ME|xxx|placeholder/i.test(m[0])) continue;
|
|
5332
|
-
const lineNum = content
|
|
5403
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5333
5404
|
findings.push({
|
|
5334
5405
|
rule: "VC119",
|
|
5335
5406
|
title: hardcodedOAuthSecret.title,
|
|
@@ -5361,7 +5432,7 @@ var missingOAuthState = {
|
|
|
5361
5432
|
if (isCommentLine(content, m.index)) continue;
|
|
5362
5433
|
const surrounding = content.substring(m.index, Math.min(content.length, m.index + 500));
|
|
5363
5434
|
if (/state\s*[=:]/i.test(surrounding)) continue;
|
|
5364
|
-
const lineNum = content
|
|
5435
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5365
5436
|
findings.push({
|
|
5366
5437
|
rule: "VC120",
|
|
5367
5438
|
title: missingOAuthState.title,
|
|
@@ -5389,7 +5460,7 @@ var unpinnedGitHubAction = {
|
|
|
5389
5460
|
let m;
|
|
5390
5461
|
while ((m = usesPattern.exec(content)) !== null) {
|
|
5391
5462
|
if (isCommentLine(content, m.index)) continue;
|
|
5392
|
-
const lineNum = content
|
|
5463
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5393
5464
|
findings.push({
|
|
5394
5465
|
rule: "VC121",
|
|
5395
5466
|
title: unpinnedGitHubAction.title,
|
|
@@ -5423,7 +5494,7 @@ var deprecatedTLS = {
|
|
|
5423
5494
|
let m;
|
|
5424
5495
|
while ((m = pat.exec(content)) !== null) {
|
|
5425
5496
|
if (isCommentLine(content, m.index)) continue;
|
|
5426
|
-
const lineNum = content
|
|
5497
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5427
5498
|
findings.push({
|
|
5428
5499
|
rule: "VC122",
|
|
5429
5500
|
title: deprecatedTLS.title,
|
|
@@ -5459,7 +5530,7 @@ var weakRSAKeySize = {
|
|
|
5459
5530
|
let m;
|
|
5460
5531
|
while ((m = pat.exec(content)) !== null) {
|
|
5461
5532
|
if (isCommentLine(content, m.index)) continue;
|
|
5462
|
-
const lineNum = content
|
|
5533
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5463
5534
|
findings.push({
|
|
5464
5535
|
rule: "VC123",
|
|
5465
5536
|
title: weakRSAKeySize.title,
|
|
@@ -5495,7 +5566,7 @@ var ecbModeEncryption = {
|
|
|
5495
5566
|
let m;
|
|
5496
5567
|
while ((m = pat.exec(content)) !== null) {
|
|
5497
5568
|
if (isCommentLine(content, m.index)) continue;
|
|
5498
|
-
const lineNum = content
|
|
5569
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5499
5570
|
findings.push({
|
|
5500
5571
|
rule: "VC124",
|
|
5501
5572
|
title: ecbModeEncryption.title,
|
|
@@ -5526,7 +5597,7 @@ var insecurePasswordReset = {
|
|
|
5526
5597
|
let m;
|
|
5527
5598
|
while ((m = weakTokens.exec(content)) !== null) {
|
|
5528
5599
|
if (isCommentLine(content, m.index)) continue;
|
|
5529
|
-
const lineNum = content
|
|
5600
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5530
5601
|
findings.push({
|
|
5531
5602
|
rule: "VC125",
|
|
5532
5603
|
title: insecurePasswordReset.title,
|
|
@@ -5543,7 +5614,7 @@ var insecurePasswordReset = {
|
|
|
5543
5614
|
if (isCommentLine(content, m.index)) continue;
|
|
5544
5615
|
const surrounding = content.substring(Math.max(0, m.index - 500), m.index);
|
|
5545
5616
|
if (!/(?:reset|forgot).*password/i.test(surrounding)) continue;
|
|
5546
|
-
const lineNum = content
|
|
5617
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5547
5618
|
findings.push({
|
|
5548
5619
|
rule: "VC125",
|
|
5549
5620
|
title: insecurePasswordReset.title,
|
|
@@ -5604,7 +5675,7 @@ var insecureHTTPMethods = {
|
|
|
5604
5675
|
if (isCommentLine(content, m.index)) continue;
|
|
5605
5676
|
const handlerBlock = content.substring(m.index, Math.min(content.length, m.index + 500));
|
|
5606
5677
|
if (/auth|authenticate|authorize|requireAuth|isAuthenticated|protect|guard|middleware|session|jwt|verify|clerk|getAuth/i.test(handlerBlock)) continue;
|
|
5607
|
-
const lineNum = content
|
|
5678
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5608
5679
|
findings.push({
|
|
5609
5680
|
rule: "VC127",
|
|
5610
5681
|
title: insecureHTTPMethods.title,
|
|
@@ -5638,7 +5709,7 @@ var httpRequestSmuggling = {
|
|
|
5638
5709
|
let m;
|
|
5639
5710
|
while ((m = pat.exec(content)) !== null) {
|
|
5640
5711
|
if (isCommentLine(content, m.index)) continue;
|
|
5641
|
-
const lineNum = content
|
|
5712
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5642
5713
|
findings.push({
|
|
5643
5714
|
rule: "VC128",
|
|
5644
5715
|
title: httpRequestSmuggling.title,
|
|
@@ -5672,7 +5743,7 @@ var unencryptedPII = {
|
|
|
5672
5743
|
let m;
|
|
5673
5744
|
while ((m = pat.exec(content)) !== null) {
|
|
5674
5745
|
if (isCommentLine(content, m.index)) continue;
|
|
5675
|
-
const lineNum = content
|
|
5746
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5676
5747
|
findings.push({
|
|
5677
5748
|
rule: "VC129",
|
|
5678
5749
|
title: unencryptedPII.title,
|
|
@@ -5704,7 +5775,7 @@ var missingAuthRateLimit = {
|
|
|
5704
5775
|
if (isCommentLine(content, m.index)) continue;
|
|
5705
5776
|
const surrounding = content.substring(Math.max(0, m.index - 300), Math.min(content.length, m.index + 300));
|
|
5706
5777
|
if (/rateLimit|rateLimiter|throttle|slowDown|express-rate-limit|rate_limit|RateLimiter|limiter/i.test(surrounding)) continue;
|
|
5707
|
-
const lineNum = content
|
|
5778
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5708
5779
|
findings.push({
|
|
5709
5780
|
rule: "VC130",
|
|
5710
5781
|
title: missingAuthRateLimit.title,
|
|
@@ -5742,7 +5813,7 @@ var vulnerableDependencies = {
|
|
|
5742
5813
|
for (const [pat, message] of vulnerablePackages) {
|
|
5743
5814
|
let m;
|
|
5744
5815
|
while ((m = pat.exec(content)) !== null) {
|
|
5745
|
-
const lineNum = content
|
|
5816
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5746
5817
|
findings.push({
|
|
5747
5818
|
rule: "VC131",
|
|
5748
5819
|
title: vulnerableDependencies.title,
|
|
@@ -5774,7 +5845,7 @@ function secretRuleCheck(content, filePath, pattern, ruleId, title, severity, fi
|
|
|
5774
5845
|
const lineStart = content.lastIndexOf("\n", m.index - 1) + 1;
|
|
5775
5846
|
const lineText = content.substring(lineStart, content.indexOf("\n", m.index));
|
|
5776
5847
|
if (PLACEHOLDER_RE.test(lineText)) continue;
|
|
5777
|
-
const lineNum = content
|
|
5848
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5778
5849
|
findings.push({
|
|
5779
5850
|
rule: ruleId,
|
|
5780
5851
|
title,
|
|
@@ -5875,7 +5946,7 @@ var hardcodedGCPServiceAccount = {
|
|
|
5875
5946
|
const findings = [];
|
|
5876
5947
|
const m = content.match(/"type"\s*:\s*"service_account"/);
|
|
5877
5948
|
if (m && m.index !== void 0) {
|
|
5878
|
-
const lineNum = content
|
|
5949
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5879
5950
|
findings.push({
|
|
5880
5951
|
rule: "VC136",
|
|
5881
5952
|
title: this.title,
|
|
@@ -5981,7 +6052,7 @@ var hardcodedDatadogKey = {
|
|
|
5981
6052
|
const lineStart = content.lastIndexOf("\n", m.index - 1) + 1;
|
|
5982
6053
|
const lineText = content.substring(lineStart, content.indexOf("\n", m.index));
|
|
5983
6054
|
if (PLACEHOLDER_RE.test(lineText)) continue;
|
|
5984
|
-
const lineNum = content
|
|
6055
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
5985
6056
|
findings.push({
|
|
5986
6057
|
rule: "VC141",
|
|
5987
6058
|
title: this.title,
|
|
@@ -6015,7 +6086,7 @@ var hardcodedVercelToken = {
|
|
|
6015
6086
|
const lineStart = content.lastIndexOf("\n", m.index - 1) + 1;
|
|
6016
6087
|
const lineText = content.substring(lineStart, content.indexOf("\n", m.index));
|
|
6017
6088
|
if (PLACEHOLDER_RE.test(lineText)) continue;
|
|
6018
|
-
const lineNum = content
|
|
6089
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6019
6090
|
findings.push({
|
|
6020
6091
|
rule: "VC142",
|
|
6021
6092
|
title: this.title,
|
|
@@ -6049,7 +6120,7 @@ var hardcodedSupabaseServiceRole = {
|
|
|
6049
6120
|
const lineStart = content.lastIndexOf("\n", m.index - 1) + 1;
|
|
6050
6121
|
const lineText = content.substring(lineStart, content.indexOf("\n", m.index));
|
|
6051
6122
|
if (PLACEHOLDER_RE.test(lineText)) continue;
|
|
6052
|
-
const lineNum = content
|
|
6123
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6053
6124
|
findings.push({
|
|
6054
6125
|
rule: "VC143",
|
|
6055
6126
|
title: this.title,
|
|
@@ -6113,7 +6184,7 @@ function contextSecretRuleCheck(content, filePath, pattern, ruleId, title, sever
|
|
|
6113
6184
|
const lineStart = content.lastIndexOf("\n", m.index - 1) + 1;
|
|
6114
6185
|
const lineText = content.substring(lineStart, content.indexOf("\n", m.index));
|
|
6115
6186
|
if (PLACEHOLDER_RE.test(lineText)) continue;
|
|
6116
|
-
const lineNum = content
|
|
6187
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6117
6188
|
findings.push({
|
|
6118
6189
|
rule: ruleId,
|
|
6119
6190
|
title,
|
|
@@ -6593,7 +6664,7 @@ var ghaPullRequestTargetCheckout = {
|
|
|
6593
6664
|
const checkoutPattern = /uses\s*:\s*actions\/checkout@[^\n]*[\s\S]{0,400}?ref\s*:\s*\$\{\{\s*github\.event\.pull_request\.head\.(?:ref|sha)\s*\}\}/g;
|
|
6594
6665
|
let m;
|
|
6595
6666
|
while ((m = checkoutPattern.exec(content)) !== null) {
|
|
6596
|
-
const lineNum = content
|
|
6667
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6597
6668
|
findings.push({
|
|
6598
6669
|
rule: "VC184",
|
|
6599
6670
|
title: ghaPullRequestTargetCheckout.title,
|
|
@@ -6677,7 +6748,7 @@ var ghaThirdPartyActionWithSecrets = {
|
|
|
6677
6748
|
const pattern = /uses\s*:\s*(?!actions\/|github\/|aws-actions\/|azure\/|google-github-actions\/|hashicorp\/)([\w\-]+\/[\w\-./]+)@[^\n]*\n[\s\S]{0,800}?with\s*:[\s\S]{0,800}?\$\{\{\s*secrets\./g;
|
|
6678
6749
|
let m;
|
|
6679
6750
|
while ((m = pattern.exec(content)) !== null) {
|
|
6680
|
-
const lineNum = content
|
|
6751
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6681
6752
|
findings.push({
|
|
6682
6753
|
rule: "VC187",
|
|
6683
6754
|
title: ghaThirdPartyActionWithSecrets.title,
|
|
@@ -6842,7 +6913,7 @@ var pyRequestsVerifyFalse = {
|
|
|
6842
6913
|
let m;
|
|
6843
6914
|
while ((m = pattern.exec(content)) !== null) {
|
|
6844
6915
|
if (isCommentLine(content, m.index)) continue;
|
|
6845
|
-
const lineNum = content
|
|
6916
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6846
6917
|
findings.push({
|
|
6847
6918
|
rule: "VC191",
|
|
6848
6919
|
title: pyRequestsVerifyFalse.title,
|
|
@@ -6873,7 +6944,7 @@ var pyJinja2AutoescapeOff = {
|
|
|
6873
6944
|
let m;
|
|
6874
6945
|
while ((m = pattern.exec(content)) !== null) {
|
|
6875
6946
|
if (isCommentLine(content, m.index)) continue;
|
|
6876
|
-
const lineNum = content
|
|
6947
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6877
6948
|
findings.push({
|
|
6878
6949
|
rule: "VC192",
|
|
6879
6950
|
title: pyJinja2AutoescapeOff.title,
|
|
@@ -6902,7 +6973,7 @@ var pyTempfileMktemp = {
|
|
|
6902
6973
|
let m;
|
|
6903
6974
|
while ((m = pattern.exec(content)) !== null) {
|
|
6904
6975
|
if (isCommentLine(content, m.index)) continue;
|
|
6905
|
-
const lineNum = content
|
|
6976
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6906
6977
|
findings.push({
|
|
6907
6978
|
rule: "VC193",
|
|
6908
6979
|
title: pyTempfileMktemp.title,
|
|
@@ -6944,7 +7015,7 @@ var pyDjangoMarkSafe = {
|
|
|
6944
7015
|
let m;
|
|
6945
7016
|
while ((m = pattern.exec(content)) !== null) {
|
|
6946
7017
|
if (isCommentLine(content, m.index)) continue;
|
|
6947
|
-
const lineNum = content
|
|
7018
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6948
7019
|
if (seenLines.has(lineNum)) continue;
|
|
6949
7020
|
seenLines.add(lineNum);
|
|
6950
7021
|
findings.push({
|
|
@@ -6981,7 +7052,7 @@ var pyParamikoAutoAdd = {
|
|
|
6981
7052
|
let m;
|
|
6982
7053
|
while ((m = pattern.exec(content)) !== null) {
|
|
6983
7054
|
if (isCommentLine(content, m.index)) continue;
|
|
6984
|
-
const lineNum = content
|
|
7055
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
6985
7056
|
if (seenLines.has(lineNum)) continue;
|
|
6986
7057
|
seenLines.add(lineNum);
|
|
6987
7058
|
findings.push({
|
|
@@ -7014,7 +7085,7 @@ var pyDjangoAllowedHostsWildcard = {
|
|
|
7014
7085
|
let m;
|
|
7015
7086
|
while ((m = pattern.exec(content)) !== null) {
|
|
7016
7087
|
if (isCommentLine(content, m.index)) continue;
|
|
7017
|
-
const lineNum = content
|
|
7088
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7018
7089
|
findings.push({
|
|
7019
7090
|
rule: "VC196",
|
|
7020
7091
|
title: pyDjangoAllowedHostsWildcard.title,
|
|
@@ -7052,7 +7123,7 @@ var pyJWTDecodeWeakConfig = {
|
|
|
7052
7123
|
if (isCommentLine(content, m.index)) continue;
|
|
7053
7124
|
const args = m[1];
|
|
7054
7125
|
if (/\balgorithms\s*=/.test(args)) continue;
|
|
7055
|
-
const lineNum = content
|
|
7126
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7056
7127
|
if (seenLines.has(lineNum)) continue;
|
|
7057
7128
|
seenLines.add(lineNum);
|
|
7058
7129
|
findings.push({
|
|
@@ -7103,7 +7174,7 @@ var llmPromptInjection = {
|
|
|
7103
7174
|
let m;
|
|
7104
7175
|
while ((m = pattern.exec(content)) !== null) {
|
|
7105
7176
|
if (isCommentLine(content, m.index)) continue;
|
|
7106
|
-
const lineNum = content
|
|
7177
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7107
7178
|
if (seenLines.has(lineNum)) continue;
|
|
7108
7179
|
seenLines.add(lineNum);
|
|
7109
7180
|
findings.push({
|
|
@@ -7142,7 +7213,7 @@ var llmSystemPromptInjection = {
|
|
|
7142
7213
|
let m;
|
|
7143
7214
|
while ((m = pattern.exec(content)) !== null) {
|
|
7144
7215
|
if (isCommentLine(content, m.index)) continue;
|
|
7145
|
-
const lineNum = content
|
|
7216
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7146
7217
|
findings.push({
|
|
7147
7218
|
rule: "VC199",
|
|
7148
7219
|
title: llmSystemPromptInjection.title,
|
|
@@ -7184,7 +7255,7 @@ var llmOutputAsHTML = {
|
|
|
7184
7255
|
let m;
|
|
7185
7256
|
while ((m = pattern.exec(content)) !== null) {
|
|
7186
7257
|
if (isCommentLine(content, m.index)) continue;
|
|
7187
|
-
const lineNum = content
|
|
7258
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7188
7259
|
if (seenLines.has(lineNum)) continue;
|
|
7189
7260
|
seenLines.add(lineNum);
|
|
7190
7261
|
findings.push({
|
|
@@ -7221,7 +7292,7 @@ var vectorStoreQueryNoUserFilter = {
|
|
|
7221
7292
|
if (/\b(?:user[_-]?id|userId|tenant[_-]?id|tenantId|org[_-]?id|orgId|owner[_-]?id|ownerId|account[_-]?id|customer[_-]?id|workspace[_-]?id)\b/i.test(args)) continue;
|
|
7222
7293
|
if (/\bnamespace\s*[:=]\s*[`"']?[^,)`"']*(?:user|tenant|org|owner|account|customer|workspace)/i.test(args)) continue;
|
|
7223
7294
|
if (/\bfilter\s*[:=][\s\S]*?(?:\buser|\btenant|\borg|\bowner|\baccount|\bcustomer|\bworkspace)/i.test(args)) continue;
|
|
7224
|
-
const lineNum = content
|
|
7295
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7225
7296
|
findings.push({
|
|
7226
7297
|
rule: "VC201",
|
|
7227
7298
|
title: vectorStoreQueryNoUserFilter.title,
|
|
@@ -7258,7 +7329,7 @@ var vectorStoreUpsertNoMetadata = {
|
|
|
7258
7329
|
if (/\bnamespace\s*[:=]\s*[`"']?[^,)`"']*(?:user|tenant|org)/i.test(args)) {
|
|
7259
7330
|
continue;
|
|
7260
7331
|
}
|
|
7261
|
-
const lineNum = content
|
|
7332
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7262
7333
|
findings.push({
|
|
7263
7334
|
rule: "VC202",
|
|
7264
7335
|
title: vectorStoreUpsertNoMetadata.title,
|
|
@@ -7312,7 +7383,7 @@ var llmCallNoMaxTokens = {
|
|
|
7312
7383
|
if (depth !== 0) continue;
|
|
7313
7384
|
const args = content.substring(openIdx + 1, i).replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "").replace(/#[^\n]*/g, "");
|
|
7314
7385
|
if (TOKEN_KW_RE.test(args)) continue;
|
|
7315
|
-
const lineNum = content
|
|
7386
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7316
7387
|
findings.push({
|
|
7317
7388
|
rule: "VC203",
|
|
7318
7389
|
title: llmCallNoMaxTokens.title,
|
|
@@ -7352,7 +7423,7 @@ var graphqlNoDepthLimit = {
|
|
|
7352
7423
|
let m;
|
|
7353
7424
|
while ((m = anchorRe.exec(content)) !== null) {
|
|
7354
7425
|
if (isCommentLine(content, m.index)) continue;
|
|
7355
|
-
const lineNum = content
|
|
7426
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7356
7427
|
findings.push({
|
|
7357
7428
|
rule: "VC204",
|
|
7358
7429
|
title: graphqlNoDepthLimit.title,
|
|
@@ -7386,7 +7457,7 @@ var graphqlNoComplexityLimit = {
|
|
|
7386
7457
|
let m;
|
|
7387
7458
|
while ((m = anchorRe.exec(content)) !== null) {
|
|
7388
7459
|
if (isCommentLine(content, m.index)) continue;
|
|
7389
|
-
const lineNum = content
|
|
7460
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7390
7461
|
findings.push({
|
|
7391
7462
|
rule: "VC205",
|
|
7392
7463
|
title: graphqlNoComplexityLimit.title,
|
|
@@ -7416,7 +7487,7 @@ var graphqlCSRFDisabled = {
|
|
|
7416
7487
|
let m;
|
|
7417
7488
|
while ((m = pattern.exec(content)) !== null) {
|
|
7418
7489
|
if (isCommentLine(content, m.index)) continue;
|
|
7419
|
-
const lineNum = content
|
|
7490
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7420
7491
|
findings.push({
|
|
7421
7492
|
rule: "VC206",
|
|
7422
7493
|
title: graphqlCSRFDisabled.title,
|
|
@@ -7512,7 +7583,7 @@ var webhookMissingIdempotency = {
|
|
|
7512
7583
|
if (/idempoten|event\.id|evt\.id|delivery_?id|alreadyProcessed|processedEvents|ON\s+CONFLICT|INSERT\s+OR\s+IGNORE|\bseen\b|\bprocessed\b/i.test(content)) return [];
|
|
7513
7584
|
const m = content.match(/constructEvent|new\s+Webhook\s*\(|verifyHeader/i);
|
|
7514
7585
|
if (!m || m.index === void 0) return [];
|
|
7515
|
-
const line = content
|
|
7586
|
+
const line = lineNumberAt(content, m.index);
|
|
7516
7587
|
return filterSilenced([{
|
|
7517
7588
|
rule: "VC209",
|
|
7518
7589
|
title: webhookMissingIdempotency.title,
|
|
@@ -7539,7 +7610,7 @@ var middlewareMatcherExcludesApi = {
|
|
|
7539
7610
|
if (!/\(\?!\s*[^)]*\bapi\b/.test(content)) return [];
|
|
7540
7611
|
const m = content.match(/matcher\s*:/);
|
|
7541
7612
|
if (!m || m.index === void 0) return [];
|
|
7542
|
-
const line = content
|
|
7613
|
+
const line = lineNumberAt(content, m.index);
|
|
7543
7614
|
return filterSilenced([{
|
|
7544
7615
|
rule: "VC210",
|
|
7545
7616
|
title: middlewareMatcherExcludesApi.title,
|
|
@@ -7577,7 +7648,7 @@ var secretInURLParam = {
|
|
|
7577
7648
|
if (isCommentLine(content, m.index)) continue;
|
|
7578
7649
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
7579
7650
|
if (isInlineSilenced(content, m.index, "VC146")) continue;
|
|
7580
|
-
const lineNum = content
|
|
7651
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7581
7652
|
findings.push({
|
|
7582
7653
|
rule: "VC146",
|
|
7583
7654
|
title: this.title,
|
|
@@ -7608,7 +7679,7 @@ var secretLoggedToConsole = {
|
|
|
7608
7679
|
while ((m = pattern.exec(content)) !== null) {
|
|
7609
7680
|
if (isCommentLine(content, m.index)) continue;
|
|
7610
7681
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
7611
|
-
const lineNum = content
|
|
7682
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7612
7683
|
findings.push({
|
|
7613
7684
|
rule: "VC147",
|
|
7614
7685
|
title: this.title,
|
|
@@ -7638,7 +7709,7 @@ var secretInErrorResponse = {
|
|
|
7638
7709
|
while ((m = pattern.exec(content)) !== null) {
|
|
7639
7710
|
if (isCommentLine(content, m.index)) continue;
|
|
7640
7711
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
7641
|
-
const lineNum = content
|
|
7712
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7642
7713
|
findings.push({
|
|
7643
7714
|
rule: "VC148",
|
|
7644
7715
|
title: this.title,
|
|
@@ -7677,7 +7748,7 @@ var secretInBundleConfig = {
|
|
|
7677
7748
|
while ((m = re.exec(content)) !== null) {
|
|
7678
7749
|
if (isCommentLine(content, m.index)) continue;
|
|
7679
7750
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
7680
|
-
const lineNum = content
|
|
7751
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7681
7752
|
findings.push({
|
|
7682
7753
|
rule: "VC149",
|
|
7683
7754
|
title: this.title,
|
|
@@ -7715,7 +7786,7 @@ var secretInHTMLAttribute = {
|
|
|
7715
7786
|
while ((m = re.exec(content)) !== null) {
|
|
7716
7787
|
if (isCommentLine(content, m.index)) continue;
|
|
7717
7788
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
7718
|
-
const lineNum = content
|
|
7789
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7719
7790
|
findings.push({
|
|
7720
7791
|
rule: "VC150",
|
|
7721
7792
|
title: this.title,
|
|
@@ -7742,9 +7813,9 @@ var secretInCLIArgument = {
|
|
|
7742
7813
|
if (!filePath.match(/\.(js|ts|jsx|tsx|py|rb)$/)) return [];
|
|
7743
7814
|
const findings = [];
|
|
7744
7815
|
const patterns = [
|
|
7745
|
-
/(?:exec|execSync|spawn|spawnSync|child_process)\s*\([^)]
|
|
7746
|
-
/(?:exec|execSync|spawn|spawnSync|child_process)\s*\([^)]
|
|
7747
|
-
/(?:subprocess|os\.system|os\.popen)\s*\([^)]
|
|
7816
|
+
/(?:exec|execSync|spawn|spawnSync|child_process)\s*\([^)]{0,500}\$\{[^}]{0,200}(?:api[_-]?key|secret|token|password|credentials)/gi,
|
|
7817
|
+
/(?:exec|execSync|spawn|spawnSync|child_process)\s*\([^)]{0,500}["']\s*\+\s*(?:api[_-]?key|secret|token|password|credentials)/gi,
|
|
7818
|
+
/(?:subprocess|os\.system|os\.popen)\s*\([^)]{0,500}\{[^}]{0,200}(?:api[_-]?key|secret|token|password|credentials)/gi
|
|
7748
7819
|
];
|
|
7749
7820
|
for (const p of patterns) {
|
|
7750
7821
|
let m;
|
|
@@ -7752,7 +7823,7 @@ var secretInCLIArgument = {
|
|
|
7752
7823
|
while ((m = re.exec(content)) !== null) {
|
|
7753
7824
|
if (isCommentLine(content, m.index)) continue;
|
|
7754
7825
|
if (isInsideFixMessage(content, m.index)) continue;
|
|
7755
|
-
const lineNum = content
|
|
7826
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7756
7827
|
findings.push({
|
|
7757
7828
|
rule: "VC151",
|
|
7758
7829
|
title: this.title,
|
|
@@ -7798,7 +7869,7 @@ var webhookSignatureVerification = {
|
|
|
7798
7869
|
if (svc.verify.test(content)) continue;
|
|
7799
7870
|
const m = content.match(/export\s+(?:async\s+)?function\s+POST/);
|
|
7800
7871
|
if (!m || m.index === void 0) continue;
|
|
7801
|
-
const lineNum = content
|
|
7872
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7802
7873
|
findings.push({
|
|
7803
7874
|
rule: "VC152",
|
|
7804
7875
|
title: `${svc.name} Webhook Missing Signature Verification`,
|
|
@@ -7865,7 +7936,7 @@ var missingRequestValidation = {
|
|
|
7865
7936
|
if (/if\s*\(\s*!(?:body|parsed|data|payload)\.|throw.*(?:missing|invalid|required)/i.test(content)) return [];
|
|
7866
7937
|
const m = content.match(/export\s+(?:async\s+)?function\s+(?:POST|PUT|PATCH)/);
|
|
7867
7938
|
if (!m || m.index === void 0) return [];
|
|
7868
|
-
const lineNum = content
|
|
7939
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7869
7940
|
return [{
|
|
7870
7941
|
rule: "VC154",
|
|
7871
7942
|
title: this.title,
|
|
@@ -7892,7 +7963,7 @@ var missingAIRateLimit = {
|
|
|
7892
7963
|
if (/rateLimit|rateLimiter|throttle|checkRateLimit|limiter|slowDown|express-rate-limit/i.test(content)) return [];
|
|
7893
7964
|
const m = content.match(/export\s+(?:async\s+)?function\s+(?:POST|GET)/i) || content.match(/\.(post|get)\s*\(/i);
|
|
7894
7965
|
if (!m || m.index === void 0) return [];
|
|
7895
|
-
const lineNum = content
|
|
7966
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7896
7967
|
return [{
|
|
7897
7968
|
rule: "VC155",
|
|
7898
7969
|
title: this.title,
|
|
@@ -7921,7 +7992,7 @@ var missingPagination = {
|
|
|
7921
7992
|
if (/findUnique|findFirst|findById|\.findOne|WHERE.*id\s*=/i.test(content)) return [];
|
|
7922
7993
|
const m = content.match(/export\s+(?:async\s+)?function\s+GET/);
|
|
7923
7994
|
if (!m || m.index === void 0) return [];
|
|
7924
|
-
const lineNum = content
|
|
7995
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7925
7996
|
return [{
|
|
7926
7997
|
rule: "VC156",
|
|
7927
7998
|
title: this.title,
|
|
@@ -7982,7 +8053,7 @@ var insecureDirectObjectReference = {
|
|
|
7982
8053
|
if (/requireUser|requireUserForApi|getServerSession|auth\(\)/i.test(content)) return [];
|
|
7983
8054
|
const m = content.match(/params\.id|params\.(?:slug|uuid)|req\.params\./);
|
|
7984
8055
|
if (!m || m.index === void 0) return [];
|
|
7985
|
-
const lineNum = content
|
|
8056
|
+
const lineNum = lineNumberAt(content, m.index);
|
|
7986
8057
|
return [{
|
|
7987
8058
|
rule: "VC158",
|
|
7988
8059
|
title: this.title,
|
|
@@ -8288,6 +8359,17 @@ function runCustomRules(content, filePath, disabledRules = [], tier = "free", ex
|
|
|
8288
8359
|
return findings;
|
|
8289
8360
|
}
|
|
8290
8361
|
if (/pro-rules-bundle|\.bundle\./i.test(filePath)) return findings;
|
|
8362
|
+
let maxLineLen = 0;
|
|
8363
|
+
{
|
|
8364
|
+
let lineStart = 0;
|
|
8365
|
+
for (let i = 0; i <= content.length; i++) {
|
|
8366
|
+
if (i === content.length || content.charCodeAt(i) === 10) {
|
|
8367
|
+
if (i - lineStart > maxLineLen) maxLineLen = i - lineStart;
|
|
8368
|
+
lineStart = i + 1;
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8372
|
+
if (maxLineLen > 5e4) return findings;
|
|
8291
8373
|
if (/onboarding|demo-data|example-vulnerable|code-sample/i.test(filePath)) return findings;
|
|
8292
8374
|
const ruleset = tier === "pro" && extraRules.length > 0 ? [...freeRules, ...extraRules] : freeRules;
|
|
8293
8375
|
for (const rule of ruleset) {
|