pqaudit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +180 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter/cbom.d.ts +8 -0
- package/dist/reporter/cbom.d.ts.map +1 -0
- package/dist/reporter/cbom.js +153 -0
- package/dist/reporter/cbom.js.map +1 -0
- package/dist/reporter/json.d.ts +3 -0
- package/dist/reporter/json.d.ts.map +1 -0
- package/dist/reporter/json.js +4 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/reporter/sarif.d.ts +7 -0
- package/dist/reporter/sarif.d.ts.map +1 -0
- package/dist/reporter/sarif.js +91 -0
- package/dist/reporter/sarif.js.map +1 -0
- package/dist/reporter/text.d.ts +3 -0
- package/dist/reporter/text.d.ts.map +1 -0
- package/dist/reporter/text.js +84 -0
- package/dist/reporter/text.js.map +1 -0
- package/dist/scanner/dependency-scanner.d.ts +3 -0
- package/dist/scanner/dependency-scanner.d.ts.map +1 -0
- package/dist/scanner/dependency-scanner.js +133 -0
- package/dist/scanner/dependency-scanner.js.map +1 -0
- package/dist/scanner/engine.d.ts +3 -0
- package/dist/scanner/engine.d.ts.map +1 -0
- package/dist/scanner/engine.js +109 -0
- package/dist/scanner/engine.js.map +1 -0
- package/dist/scanner/file-scanner.d.ts +5 -0
- package/dist/scanner/file-scanner.d.ts.map +1 -0
- package/dist/scanner/file-scanner.js +163 -0
- package/dist/scanner/file-scanner.js.map +1 -0
- package/dist/scanner/rules.d.ts +4 -0
- package/dist/scanner/rules.d.ts.map +1 -0
- package/dist/scanner/rules.js +25 -0
- package/dist/scanner/rules.js.map +1 -0
- package/dist/types.d.ts +102 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
- package/rules/crypto-patterns.yaml +350 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
const SEVERITY_COLORS = {
|
|
3
|
+
critical: chalk.red.bold,
|
|
4
|
+
high: chalk.yellow.bold,
|
|
5
|
+
medium: chalk.yellow,
|
|
6
|
+
low: chalk.blue,
|
|
7
|
+
safe: chalk.green,
|
|
8
|
+
};
|
|
9
|
+
const SEVERITY_ICONS = {
|
|
10
|
+
critical: "!!",
|
|
11
|
+
high: "!",
|
|
12
|
+
medium: "~",
|
|
13
|
+
low: "-",
|
|
14
|
+
safe: "ok",
|
|
15
|
+
};
|
|
16
|
+
export function formatText(result) {
|
|
17
|
+
const lines = [];
|
|
18
|
+
lines.push("");
|
|
19
|
+
lines.push(chalk.bold(" pqaudit — Post-Quantum Cryptography Readiness Scanner"));
|
|
20
|
+
lines.push(chalk.dim(` Scanned: ${result.target}`));
|
|
21
|
+
lines.push(chalk.dim(` Date: ${result.timestamp}`));
|
|
22
|
+
lines.push("");
|
|
23
|
+
// Summary bar
|
|
24
|
+
const s = result.summary;
|
|
25
|
+
if (s.pqcReady) {
|
|
26
|
+
lines.push(chalk.green.bold(" PQC READY — No critical or high-severity findings"));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
lines.push(chalk.red.bold(" NOT PQC READY — Quantum-vulnerable cryptography detected"));
|
|
30
|
+
}
|
|
31
|
+
lines.push("");
|
|
32
|
+
// Stats
|
|
33
|
+
lines.push(` Files scanned: ${s.filesScanned} | Findings: ${s.findingsTotal}`);
|
|
34
|
+
lines.push(` ${chalk.red(`Critical: ${s.bySeverity.critical}`)} ` +
|
|
35
|
+
`${chalk.yellow(`High: ${s.bySeverity.high}`)} ` +
|
|
36
|
+
`${chalk.yellow(`Medium: ${s.bySeverity.medium}`)} ` +
|
|
37
|
+
`${chalk.blue(`Low: ${s.bySeverity.low}`)} ` +
|
|
38
|
+
`${chalk.green(`Safe: ${s.bySeverity.safe}`)}`);
|
|
39
|
+
lines.push("");
|
|
40
|
+
if (result.findings.length === 0) {
|
|
41
|
+
lines.push(" No findings.");
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|
|
44
|
+
// Group by severity
|
|
45
|
+
const grouped = groupBySeverity(result.findings);
|
|
46
|
+
for (const [severity, findings] of grouped) {
|
|
47
|
+
if (findings.length === 0)
|
|
48
|
+
continue;
|
|
49
|
+
const color = SEVERITY_COLORS[severity];
|
|
50
|
+
lines.push(color(` --- ${severity.toUpperCase()} (${findings.length}) ---`));
|
|
51
|
+
lines.push("");
|
|
52
|
+
for (const f of findings) {
|
|
53
|
+
const icon = SEVERITY_ICONS[f.severity];
|
|
54
|
+
const loc = f.location.line
|
|
55
|
+
? `${f.location.file}:${f.location.line}`
|
|
56
|
+
: f.location.file;
|
|
57
|
+
lines.push(color(` [${icon}] ${f.algorithm} — ${f.description}`));
|
|
58
|
+
lines.push(chalk.dim(` ${loc}`));
|
|
59
|
+
if (f.location.snippet) {
|
|
60
|
+
lines.push(chalk.dim(` > ${f.location.snippet}`));
|
|
61
|
+
}
|
|
62
|
+
if (f.replacement) {
|
|
63
|
+
lines.push(chalk.cyan(` Fix: ${f.replacement}`));
|
|
64
|
+
}
|
|
65
|
+
lines.push(chalk.dim(` Confidence: ${Math.round(f.confidence * 100)}% | Effort: ${f.effort} | Via: ${f.detectionMethod}`));
|
|
66
|
+
lines.push("");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return lines.join("\n");
|
|
70
|
+
}
|
|
71
|
+
function groupBySeverity(findings) {
|
|
72
|
+
const groups = {
|
|
73
|
+
critical: [],
|
|
74
|
+
high: [],
|
|
75
|
+
medium: [],
|
|
76
|
+
low: [],
|
|
77
|
+
safe: [],
|
|
78
|
+
};
|
|
79
|
+
for (const f of findings) {
|
|
80
|
+
groups[f.severity].push(f);
|
|
81
|
+
}
|
|
82
|
+
return Object.entries(groups);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/reporter/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-scanner.d.ts","sourceRoot":"","sources":["../../src/scanner/dependency-scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAoG3C,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CAuChE"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Known npm packages and their cryptographic implications */
|
|
4
|
+
const KNOWN_CRYPTO_PACKAGES = {
|
|
5
|
+
// PQC-safe libraries
|
|
6
|
+
"@noble/post-quantum": {
|
|
7
|
+
algorithm: "ML-KEM / ML-DSA",
|
|
8
|
+
severity: "safe",
|
|
9
|
+
category: "kem",
|
|
10
|
+
description: "Post-quantum cryptography library (ML-KEM, ML-DSA, SLH-DSA)",
|
|
11
|
+
replacement: null,
|
|
12
|
+
},
|
|
13
|
+
// Quantum-vulnerable signature libraries
|
|
14
|
+
"@noble/ed25519": {
|
|
15
|
+
algorithm: "Ed25519",
|
|
16
|
+
severity: "critical",
|
|
17
|
+
category: "signature",
|
|
18
|
+
description: "Ed25519 signatures — vulnerable to Shor's algorithm",
|
|
19
|
+
replacement: "ML-DSA-65 via @noble/post-quantum",
|
|
20
|
+
},
|
|
21
|
+
"@noble/secp256k1": {
|
|
22
|
+
algorithm: "secp256k1 (ECDSA)",
|
|
23
|
+
severity: "critical",
|
|
24
|
+
category: "signature",
|
|
25
|
+
description: "secp256k1 ECDSA — vulnerable to Shor's algorithm",
|
|
26
|
+
replacement: "ML-DSA-65 via @noble/post-quantum",
|
|
27
|
+
},
|
|
28
|
+
"tweetnacl": {
|
|
29
|
+
algorithm: "Ed25519 / X25519",
|
|
30
|
+
severity: "critical",
|
|
31
|
+
category: "signature",
|
|
32
|
+
description: "NaCl crypto (Ed25519 signatures, X25519 key exchange) — both quantum-vulnerable",
|
|
33
|
+
replacement: "ML-DSA-65 + ML-KEM-768 via @noble/post-quantum",
|
|
34
|
+
},
|
|
35
|
+
"elliptic": {
|
|
36
|
+
algorithm: "ECDSA / ECDH",
|
|
37
|
+
severity: "critical",
|
|
38
|
+
category: "signature",
|
|
39
|
+
description: "Elliptic curve library — all ECC is quantum-vulnerable",
|
|
40
|
+
replacement: "ML-DSA-65 + ML-KEM-768",
|
|
41
|
+
},
|
|
42
|
+
"node-rsa": {
|
|
43
|
+
algorithm: "RSA",
|
|
44
|
+
severity: "critical",
|
|
45
|
+
category: "kem",
|
|
46
|
+
description: "RSA encryption/signatures — vulnerable to Shor's algorithm",
|
|
47
|
+
replacement: "ML-KEM-768 + ML-DSA-65",
|
|
48
|
+
},
|
|
49
|
+
"jsonwebtoken": {
|
|
50
|
+
algorithm: "RS256/ES256 (likely)",
|
|
51
|
+
severity: "critical",
|
|
52
|
+
category: "signature",
|
|
53
|
+
description: "JWT library — likely uses RSA or ECDSA for signing",
|
|
54
|
+
replacement: "Consider ML-DSA-based JWT signing when IETF PQC JWT standards emerge",
|
|
55
|
+
},
|
|
56
|
+
"jose": {
|
|
57
|
+
algorithm: "RS256/ES256 (configurable)",
|
|
58
|
+
severity: "critical",
|
|
59
|
+
category: "signature",
|
|
60
|
+
description: "JOSE/JWT library — supports RSA and ECDSA signing",
|
|
61
|
+
replacement: "Monitor IETF PQC JWT standards progress",
|
|
62
|
+
},
|
|
63
|
+
// Solana/blockchain (quantum-vulnerable by design)
|
|
64
|
+
"@solana/web3.js": {
|
|
65
|
+
algorithm: "Ed25519 (Solana)",
|
|
66
|
+
severity: "critical",
|
|
67
|
+
category: "signature",
|
|
68
|
+
description: "Solana Web3 — all Solana keys are Ed25519, quantum-vulnerable",
|
|
69
|
+
replacement: "Blocked by Solana ecosystem PQC migration. Monitor Solana PQC proposals.",
|
|
70
|
+
},
|
|
71
|
+
"ethers": {
|
|
72
|
+
algorithm: "secp256k1 (Ethereum)",
|
|
73
|
+
severity: "critical",
|
|
74
|
+
category: "signature",
|
|
75
|
+
description: "Ethers.js — Ethereum uses secp256k1 ECDSA, quantum-vulnerable",
|
|
76
|
+
replacement: "Blocked by Ethereum PQC migration. Monitor EIP proposals.",
|
|
77
|
+
},
|
|
78
|
+
"web3": {
|
|
79
|
+
algorithm: "secp256k1 (Ethereum)",
|
|
80
|
+
severity: "critical",
|
|
81
|
+
category: "signature",
|
|
82
|
+
description: "Web3.js — Ethereum uses secp256k1 ECDSA, quantum-vulnerable",
|
|
83
|
+
replacement: "Blocked by Ethereum PQC migration. Monitor EIP proposals.",
|
|
84
|
+
},
|
|
85
|
+
// Symmetric / safe
|
|
86
|
+
"libsodium-wrappers": {
|
|
87
|
+
algorithm: "XChaCha20-Poly1305 / Ed25519",
|
|
88
|
+
severity: "critical",
|
|
89
|
+
category: "signature",
|
|
90
|
+
description: "libsodium — symmetric crypto is safe but Ed25519/X25519 are quantum-vulnerable",
|
|
91
|
+
replacement: "Audit usage: keep symmetric ops, migrate asymmetric to PQC",
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
export function scanNpmDependencies(targetDir) {
|
|
95
|
+
const packageJsonPath = join(targetDir, "package.json");
|
|
96
|
+
if (!existsSync(packageJsonPath))
|
|
97
|
+
return [];
|
|
98
|
+
let pkg;
|
|
99
|
+
try {
|
|
100
|
+
pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
const findings = [];
|
|
106
|
+
const allDeps = {
|
|
107
|
+
...pkg.dependencies,
|
|
108
|
+
...pkg.devDependencies,
|
|
109
|
+
};
|
|
110
|
+
for (const [name, version] of Object.entries(allDeps)) {
|
|
111
|
+
const known = KNOWN_CRYPTO_PACKAGES[name];
|
|
112
|
+
if (!known)
|
|
113
|
+
continue;
|
|
114
|
+
findings.push({
|
|
115
|
+
ruleId: `DEP_${name.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase()}`,
|
|
116
|
+
description: known.description,
|
|
117
|
+
severity: known.severity,
|
|
118
|
+
category: known.category,
|
|
119
|
+
algorithm: known.algorithm,
|
|
120
|
+
replacement: known.replacement,
|
|
121
|
+
effort: "complex",
|
|
122
|
+
location: {
|
|
123
|
+
file: "package.json",
|
|
124
|
+
snippet: `"${name}": "${version}"`,
|
|
125
|
+
},
|
|
126
|
+
detectionMethod: "dependency",
|
|
127
|
+
confidence: 0.95,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return findings;
|
|
131
|
+
}
|
|
132
|
+
// TODO: Add scanCargoDependencies, scanGradleDependencies, scanPipDependencies
|
|
133
|
+
//# sourceMappingURL=dependency-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-scanner.js","sourceRoot":"","sources":["../../src/scanner/dependency-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/scanner/engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,UAAU,EACV,UAAU,EAIX,MAAM,aAAa,CAAC;AA0BrB,wBAAsB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAmElE"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { resolve, relative } from "node:path";
|
|
2
|
+
import { glob } from "glob";
|
|
3
|
+
import { loadRules } from "./rules.js";
|
|
4
|
+
import { scanFile } from "./file-scanner.js";
|
|
5
|
+
import { scanNpmDependencies } from "./dependency-scanner.js";
|
|
6
|
+
const DEFAULT_EXCLUDE = [
|
|
7
|
+
"**/node_modules/**",
|
|
8
|
+
"**/dist/**",
|
|
9
|
+
"**/build/**",
|
|
10
|
+
"**/.git/**",
|
|
11
|
+
"**/vendor/**",
|
|
12
|
+
"**/target/**",
|
|
13
|
+
"**/__pycache__/**",
|
|
14
|
+
"**/.venv/**",
|
|
15
|
+
"**/coverage/**",
|
|
16
|
+
"**/*.min.js",
|
|
17
|
+
"**/*.map",
|
|
18
|
+
"**/package-lock.json",
|
|
19
|
+
"**/yarn.lock",
|
|
20
|
+
"**/pnpm-lock.yaml",
|
|
21
|
+
"**/Cargo.lock",
|
|
22
|
+
];
|
|
23
|
+
const SOURCE_EXTENSIONS = "**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts,py,go,rs,java,kt,kts,cs,c,h,cpp,cc,hpp,swift,rb,php,toml,yaml,yml,json,xml,conf,cfg,ini,env,pem,crt,cer}";
|
|
24
|
+
export async function scan(config) {
|
|
25
|
+
const target = resolve(config.target);
|
|
26
|
+
const rules = loadRules(config.rulesDir);
|
|
27
|
+
// Discover files
|
|
28
|
+
const excludePatterns = [...DEFAULT_EXCLUDE, ...(config.exclude ?? [])];
|
|
29
|
+
const includePatterns = config.include ?? [SOURCE_EXTENSIONS];
|
|
30
|
+
const files = [];
|
|
31
|
+
for (const pattern of includePatterns) {
|
|
32
|
+
const matched = await glob(pattern, {
|
|
33
|
+
cwd: target,
|
|
34
|
+
absolute: true,
|
|
35
|
+
ignore: excludePatterns,
|
|
36
|
+
nodir: true,
|
|
37
|
+
});
|
|
38
|
+
files.push(...matched);
|
|
39
|
+
}
|
|
40
|
+
// Deduplicate
|
|
41
|
+
const uniqueFiles = [...new Set(files)];
|
|
42
|
+
// Scan files
|
|
43
|
+
const allFindings = [];
|
|
44
|
+
for (const file of uniqueFiles) {
|
|
45
|
+
const rel = relative(target, file);
|
|
46
|
+
const fileFindings = scanFile(file, rel, rules);
|
|
47
|
+
allFindings.push(...fileFindings);
|
|
48
|
+
}
|
|
49
|
+
// Scan dependencies
|
|
50
|
+
if (config.scanDependencies) {
|
|
51
|
+
const depFindings = scanNpmDependencies(target);
|
|
52
|
+
allFindings.push(...depFindings);
|
|
53
|
+
}
|
|
54
|
+
// Filter by minimum severity
|
|
55
|
+
const severityOrder = {
|
|
56
|
+
critical: 0,
|
|
57
|
+
high: 1,
|
|
58
|
+
medium: 2,
|
|
59
|
+
low: 3,
|
|
60
|
+
safe: 4,
|
|
61
|
+
};
|
|
62
|
+
const minLevel = severityOrder[config.minSeverity];
|
|
63
|
+
const filtered = allFindings.filter((f) => severityOrder[f.severity] <= minLevel);
|
|
64
|
+
// Sort: critical first, then by file
|
|
65
|
+
filtered.sort((a, b) => {
|
|
66
|
+
const sevDiff = severityOrder[a.severity] - severityOrder[b.severity];
|
|
67
|
+
if (sevDiff !== 0)
|
|
68
|
+
return sevDiff;
|
|
69
|
+
return a.location.file.localeCompare(b.location.file);
|
|
70
|
+
});
|
|
71
|
+
// Build summary
|
|
72
|
+
const summary = buildSummary(filtered, uniqueFiles.length);
|
|
73
|
+
return {
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
75
|
+
target: config.target,
|
|
76
|
+
findings: filtered,
|
|
77
|
+
summary,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function buildSummary(findings, filesScanned) {
|
|
81
|
+
const bySeverity = {
|
|
82
|
+
critical: 0,
|
|
83
|
+
high: 0,
|
|
84
|
+
medium: 0,
|
|
85
|
+
low: 0,
|
|
86
|
+
safe: 0,
|
|
87
|
+
};
|
|
88
|
+
const byCategory = {
|
|
89
|
+
kem: 0,
|
|
90
|
+
signature: 0,
|
|
91
|
+
hash: 0,
|
|
92
|
+
symmetric: 0,
|
|
93
|
+
protocol: 0,
|
|
94
|
+
kdf: 0,
|
|
95
|
+
};
|
|
96
|
+
for (const f of findings) {
|
|
97
|
+
bySeverity[f.severity]++;
|
|
98
|
+
byCategory[f.category]++;
|
|
99
|
+
}
|
|
100
|
+
const pqcReady = bySeverity.critical === 0 && bySeverity.high === 0;
|
|
101
|
+
return {
|
|
102
|
+
filesScanned,
|
|
103
|
+
findingsTotal: findings.length,
|
|
104
|
+
bySeverity,
|
|
105
|
+
byCategory,
|
|
106
|
+
pqcReady,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/scanner/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DetectionRule, Finding } from "../types.js";
|
|
2
|
+
export declare function getLanguage(filePath: string): string | null;
|
|
3
|
+
export declare function isBinary(filePath: string): boolean;
|
|
4
|
+
export declare function scanFile(filePath: string, relativePath: string, rules: DetectionRule[]): Finding[];
|
|
5
|
+
//# sourceMappingURL=file-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-scanner.d.ts","sourceRoot":"","sources":["../../src/scanner/file-scanner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,OAAO,EAGR,MAAM,aAAa,CAAC;AAqErB,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG3D;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,aAAa,EAAE,GACrB,OAAO,EAAE,CA4EX"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { compilePatterns } from "./rules.js";
|
|
3
|
+
/** File extensions to language mapping */
|
|
4
|
+
const LANG_MAP = {
|
|
5
|
+
".js": "javascript",
|
|
6
|
+
".mjs": "javascript",
|
|
7
|
+
".cjs": "javascript",
|
|
8
|
+
".jsx": "javascript",
|
|
9
|
+
".ts": "typescript",
|
|
10
|
+
".tsx": "typescript",
|
|
11
|
+
".mts": "typescript",
|
|
12
|
+
".cts": "typescript",
|
|
13
|
+
".py": "python",
|
|
14
|
+
".go": "go",
|
|
15
|
+
".rs": "rust",
|
|
16
|
+
".java": "java",
|
|
17
|
+
".kt": "kotlin",
|
|
18
|
+
".kts": "kotlin",
|
|
19
|
+
".cs": "csharp",
|
|
20
|
+
".c": "c",
|
|
21
|
+
".h": "c",
|
|
22
|
+
".cpp": "cpp",
|
|
23
|
+
".cc": "cpp",
|
|
24
|
+
".hpp": "cpp",
|
|
25
|
+
".swift": "swift",
|
|
26
|
+
".rb": "ruby",
|
|
27
|
+
".php": "php",
|
|
28
|
+
".toml": "config",
|
|
29
|
+
".yaml": "config",
|
|
30
|
+
".yml": "config",
|
|
31
|
+
".json": "config",
|
|
32
|
+
".xml": "config",
|
|
33
|
+
".conf": "config",
|
|
34
|
+
".cfg": "config",
|
|
35
|
+
".ini": "config",
|
|
36
|
+
".env": "config",
|
|
37
|
+
".pem": "certificate",
|
|
38
|
+
".crt": "certificate",
|
|
39
|
+
".cer": "certificate",
|
|
40
|
+
};
|
|
41
|
+
const BINARY_EXTENSIONS = new Set([
|
|
42
|
+
".png",
|
|
43
|
+
".jpg",
|
|
44
|
+
".jpeg",
|
|
45
|
+
".gif",
|
|
46
|
+
".ico",
|
|
47
|
+
".woff",
|
|
48
|
+
".woff2",
|
|
49
|
+
".ttf",
|
|
50
|
+
".eot",
|
|
51
|
+
".zip",
|
|
52
|
+
".gz",
|
|
53
|
+
".tar",
|
|
54
|
+
".jar",
|
|
55
|
+
".class",
|
|
56
|
+
".so",
|
|
57
|
+
".dylib",
|
|
58
|
+
".dll",
|
|
59
|
+
".exe",
|
|
60
|
+
".o",
|
|
61
|
+
".a",
|
|
62
|
+
".wasm",
|
|
63
|
+
".mp3",
|
|
64
|
+
".mp4",
|
|
65
|
+
".pdf",
|
|
66
|
+
]);
|
|
67
|
+
export function getLanguage(filePath) {
|
|
68
|
+
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
69
|
+
return LANG_MAP[ext] ?? null;
|
|
70
|
+
}
|
|
71
|
+
export function isBinary(filePath) {
|
|
72
|
+
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
73
|
+
return BINARY_EXTENSIONS.has(ext);
|
|
74
|
+
}
|
|
75
|
+
export function scanFile(filePath, relativePath, rules) {
|
|
76
|
+
if (isBinary(filePath))
|
|
77
|
+
return [];
|
|
78
|
+
const language = getLanguage(filePath);
|
|
79
|
+
const compiledRules = compilePatterns(rules);
|
|
80
|
+
const findings = [];
|
|
81
|
+
let content;
|
|
82
|
+
try {
|
|
83
|
+
content = readFileSync(filePath, "utf-8");
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
// Skip very large files (likely generated/vendor)
|
|
89
|
+
if (content.length > 1_000_000)
|
|
90
|
+
return [];
|
|
91
|
+
const lines = content.split("\n");
|
|
92
|
+
for (const [rule, regexes] of compiledRules) {
|
|
93
|
+
// Skip rules that don't apply to this language
|
|
94
|
+
if (rule.languages.length > 0 &&
|
|
95
|
+
language &&
|
|
96
|
+
!rule.languages.includes(language)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
100
|
+
const line = lines[lineIdx];
|
|
101
|
+
for (const regex of regexes) {
|
|
102
|
+
// Reset regex state (global flag)
|
|
103
|
+
regex.lastIndex = 0;
|
|
104
|
+
const match = regex.exec(line);
|
|
105
|
+
if (match) {
|
|
106
|
+
// Avoid duplicate findings for same rule on same line
|
|
107
|
+
const isDupe = findings.some((f) => f.ruleId === rule.id &&
|
|
108
|
+
f.location.file === relativePath &&
|
|
109
|
+
f.location.line === lineIdx + 1);
|
|
110
|
+
if (!isDupe) {
|
|
111
|
+
const location = {
|
|
112
|
+
file: relativePath,
|
|
113
|
+
line: lineIdx + 1,
|
|
114
|
+
column: match.index + 1,
|
|
115
|
+
snippet: line.trim().slice(0, 120),
|
|
116
|
+
};
|
|
117
|
+
findings.push({
|
|
118
|
+
ruleId: rule.id,
|
|
119
|
+
description: rule.description,
|
|
120
|
+
severity: rule.severity,
|
|
121
|
+
category: rule.category,
|
|
122
|
+
algorithm: rule.algorithm,
|
|
123
|
+
replacement: rule.replacement,
|
|
124
|
+
effort: rule.effort,
|
|
125
|
+
location,
|
|
126
|
+
detectionMethod: "regex",
|
|
127
|
+
confidence: computeConfidence(rule, line, language),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Don't check more patterns from this rule on this line
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return findings;
|
|
137
|
+
}
|
|
138
|
+
/** Compute confidence based on context clues */
|
|
139
|
+
function computeConfidence(rule, line, language) {
|
|
140
|
+
let confidence = 0.7; // Base confidence for regex match
|
|
141
|
+
// Higher confidence if it looks like a code import
|
|
142
|
+
if (/(?:import|require|from|include|use)\b/.test(line)) {
|
|
143
|
+
confidence = 0.9;
|
|
144
|
+
}
|
|
145
|
+
// Higher confidence if it's a function call with the algorithm
|
|
146
|
+
if (/\(.*['"].*['"]\)/.test(line)) {
|
|
147
|
+
confidence = 0.85;
|
|
148
|
+
}
|
|
149
|
+
// Lower confidence in comments
|
|
150
|
+
if (/^\s*(?:\/\/|#|\/\*|\*|--|;)/.test(line)) {
|
|
151
|
+
confidence = 0.3;
|
|
152
|
+
}
|
|
153
|
+
// Lower confidence in strings that might be documentation
|
|
154
|
+
if (language === null) {
|
|
155
|
+
confidence *= 0.8;
|
|
156
|
+
}
|
|
157
|
+
// Safe findings get high confidence (we want to track them)
|
|
158
|
+
if (rule.severity === "safe") {
|
|
159
|
+
confidence = Math.max(confidence, 0.8);
|
|
160
|
+
}
|
|
161
|
+
return Math.round(confidence * 100) / 100;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=file-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-scanner.js","sourceRoot":"","sources":["../../src/scanner/file-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/scanner/rules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAOjD,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAa7D;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,aAAa,EAAE,GACrB,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC,CAS9B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
const DEFAULT_RULES_PATH = resolve(import.meta.dirname, "../../rules/crypto-patterns.yaml");
|
|
5
|
+
export function loadRules(rulesPath) {
|
|
6
|
+
const path = rulesPath ?? DEFAULT_RULES_PATH;
|
|
7
|
+
const raw = readFileSync(path, "utf-8");
|
|
8
|
+
const parsed = parseYaml(raw);
|
|
9
|
+
// Validate and compile patterns
|
|
10
|
+
for (const rule of parsed) {
|
|
11
|
+
if (!rule.id || !rule.patterns?.length) {
|
|
12
|
+
throw new Error(`Invalid rule: missing id or patterns in ${path}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
export function compilePatterns(rules) {
|
|
18
|
+
const compiled = new Map();
|
|
19
|
+
for (const rule of rules) {
|
|
20
|
+
const regexes = rule.patterns.map((p) => new RegExp(p, "gi"));
|
|
21
|
+
compiled.set(rule, regexes);
|
|
22
|
+
}
|
|
23
|
+
return compiled;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/scanner/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAG1C,MAAM,kBAAkB,GAAG,OAAO,CAChC,MAAM,CAAC,IAAI,CAAC,OAAO,EACnB,kCAAkC,CACnC,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,SAAkB;IAC1C,MAAM,IAAI,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAoB,CAAC;IAEjD,gCAAgC;IAChC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,KAAsB;IAEtB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEpD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9D,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|