@quantakrypto/core 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/README.md +337 -0
- package/dist/baseline.d.ts +37 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +99 -0
- package/dist/baseline.js.map +1 -0
- package/dist/cbom.d.ts +25 -0
- package/dist/cbom.d.ts.map +1 -0
- package/dist/cbom.js +131 -0
- package/dist/cbom.js.map +1 -0
- package/dist/changed.d.ts +13 -0
- package/dist/changed.d.ts.map +1 -0
- package/dist/changed.js +67 -0
- package/dist/changed.js.map +1 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +232 -0
- package/dist/config.js.map +1 -0
- package/dist/cwe.d.ts +16 -0
- package/dist/cwe.d.ts.map +1 -0
- package/dist/cwe.js +16 -0
- package/dist/cwe.js.map +1 -0
- package/dist/dependencies.d.ts +25 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +276 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/detect-utils.d.ts +63 -0
- package/dist/detect-utils.d.ts.map +1 -0
- package/dist/detect-utils.js +113 -0
- package/dist/detect-utils.js.map +1 -0
- package/dist/detectors/pem.d.ts +9 -0
- package/dist/detectors/pem.d.ts.map +1 -0
- package/dist/detectors/pem.js +137 -0
- package/dist/detectors/pem.js.map +1 -0
- package/dist/detectors/source.d.ts +25 -0
- package/dist/detectors/source.d.ts.map +1 -0
- package/dist/detectors/source.js +575 -0
- package/dist/detectors/source.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory.d.ts +15 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +74 -0
- package/dist/inventory.js.map +1 -0
- package/dist/parallel.d.ts +34 -0
- package/dist/parallel.d.ts.map +1 -0
- package/dist/parallel.js +237 -0
- package/dist/parallel.js.map +1 -0
- package/dist/registry.d.ts +42 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +51 -0
- package/dist/registry.js.map +1 -0
- package/dist/remediation.d.ts +42 -0
- package/dist/remediation.d.ts.map +1 -0
- package/dist/remediation.js +131 -0
- package/dist/remediation.js.map +1 -0
- package/dist/report.d.ts +24 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +286 -0
- package/dist/report.js.map +1 -0
- package/dist/scan-worker.d.ts +2 -0
- package/dist/scan-worker.d.ts.map +1 -0
- package/dist/scan-worker.js +63 -0
- package/dist/scan-worker.js.map +1 -0
- package/dist/scan.d.ts +27 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +168 -0
- package/dist/scan.js.map +1 -0
- package/dist/types.d.ts +190 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/dist/walk.d.ts +37 -0
- package/dist/walk.d.ts.map +1 -0
- package/dist/walk.js +260 -0
- package/dist/walk.js.map +1 -0
- package/package.json +40 -0
- package/src/baseline.ts +111 -0
- package/src/cbom.ts +166 -0
- package/src/changed.ts +76 -0
- package/src/config.ts +295 -0
- package/src/cwe.ts +20 -0
- package/src/dependencies.ts +299 -0
- package/src/detect-utils.ts +157 -0
- package/src/detectors/pem.ts +162 -0
- package/src/detectors/source.ts +733 -0
- package/src/index.ts +79 -0
- package/src/inventory.ts +94 -0
- package/src/parallel.ts +288 -0
- package/src/registry.ts +71 -0
- package/src/remediation.ts +173 -0
- package/src/report.ts +340 -0
- package/src/scan-worker.ts +80 -0
- package/src/scan.ts +187 -0
- package/src/types.ts +224 -0
- package/src/version.ts +6 -0
- package/src/walk.ts +289 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { makeFinding } from "./detect-utils.js";
|
|
2
|
+
import { remediationText } from "./remediation.js";
|
|
3
|
+
import { CWE_BROKEN_CRYPTO } from "./cwe.js";
|
|
4
|
+
/** Known quantum-vulnerable npm dependencies. */
|
|
5
|
+
export const vulnerableDependencies = [
|
|
6
|
+
{
|
|
7
|
+
name: "node-forge",
|
|
8
|
+
ecosystem: "npm",
|
|
9
|
+
reason: "Pure-JS implementation of RSA, RSA-OAEP, and X.509 PKI.",
|
|
10
|
+
algorithms: ["RSA"],
|
|
11
|
+
severity: "high",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "elliptic",
|
|
15
|
+
ecosystem: "npm",
|
|
16
|
+
reason: "Elliptic-curve ECDSA/ECDH (secp256k1, p256, ed25519).",
|
|
17
|
+
algorithms: ["ECDSA", "ECDH", "EdDSA"],
|
|
18
|
+
severity: "high",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "jsrsasign",
|
|
22
|
+
ecosystem: "npm",
|
|
23
|
+
reason: "RSA/ECDSA/DSA signing, JWT, and X.509 in pure JS.",
|
|
24
|
+
algorithms: ["RSA", "ECDSA", "DSA"],
|
|
25
|
+
severity: "high",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "node-rsa",
|
|
29
|
+
ecosystem: "npm",
|
|
30
|
+
reason: "Classical RSA encryption and signing.",
|
|
31
|
+
algorithms: ["RSA"],
|
|
32
|
+
severity: "high",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "ursa",
|
|
36
|
+
ecosystem: "npm",
|
|
37
|
+
reason: "OpenSSL-backed RSA encryption and signing bindings.",
|
|
38
|
+
algorithms: ["RSA"],
|
|
39
|
+
severity: "high",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "sshpk",
|
|
43
|
+
ecosystem: "npm",
|
|
44
|
+
reason: "Parses/handles SSH and PEM keys (RSA, ECDSA, Ed25519, DSA).",
|
|
45
|
+
algorithms: ["RSA", "ECDSA", "EdDSA", "DSA"],
|
|
46
|
+
severity: "medium",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "jsonwebtoken",
|
|
50
|
+
ecosystem: "npm",
|
|
51
|
+
reason: "JWTs commonly signed with RS256/ES256 (classical RSA/ECDSA).",
|
|
52
|
+
algorithms: ["RSA", "ECDSA"],
|
|
53
|
+
severity: "high",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "jose",
|
|
57
|
+
ecosystem: "npm",
|
|
58
|
+
reason: "JWS/JWE with classical RSA-OAEP, RSA-PSS, ECDH-ES and ECDSA.",
|
|
59
|
+
algorithms: ["RSA", "ECDH", "ECDSA", "EdDSA"],
|
|
60
|
+
severity: "high",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "jws",
|
|
64
|
+
ecosystem: "npm",
|
|
65
|
+
reason: "JSON Web Signatures using classical RS/ES algorithms.",
|
|
66
|
+
algorithms: ["RSA", "ECDSA"],
|
|
67
|
+
severity: "high",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "eccrypto",
|
|
71
|
+
ecosystem: "npm",
|
|
72
|
+
reason: "ECIES (ECDH-based) encryption and ECDSA signatures.",
|
|
73
|
+
algorithms: ["ECIES", "ECDH", "ECDSA"],
|
|
74
|
+
severity: "high",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "secp256k1",
|
|
78
|
+
ecosystem: "npm",
|
|
79
|
+
reason: "secp256k1 ECDSA/ECDH bindings (blockchain keys).",
|
|
80
|
+
algorithms: ["ECDSA", "ECDH"],
|
|
81
|
+
severity: "high",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "tweetnacl",
|
|
85
|
+
ecosystem: "npm",
|
|
86
|
+
reason: "X25519 key exchange and Ed25519 signatures (modern but classical).",
|
|
87
|
+
algorithms: ["X25519", "EdDSA"],
|
|
88
|
+
severity: "low",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "ed25519",
|
|
92
|
+
ecosystem: "npm",
|
|
93
|
+
reason: "Ed25519 signatures (classical).",
|
|
94
|
+
algorithms: ["EdDSA"],
|
|
95
|
+
severity: "low",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "@noble/curves",
|
|
99
|
+
ecosystem: "npm",
|
|
100
|
+
reason: "Audited classical curves: ECDSA, ECDH, Ed25519, X25519, secp256k1.",
|
|
101
|
+
algorithms: ["ECDSA", "ECDH", "EdDSA", "X25519"],
|
|
102
|
+
severity: "medium",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "@noble/secp256k1",
|
|
106
|
+
ecosystem: "npm",
|
|
107
|
+
reason: "secp256k1 ECDSA/ECDH (classical).",
|
|
108
|
+
algorithms: ["ECDSA", "ECDH"],
|
|
109
|
+
severity: "medium",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "@noble/ed25519",
|
|
113
|
+
ecosystem: "npm",
|
|
114
|
+
reason: "Ed25519 signatures and X25519 key exchange (classical).",
|
|
115
|
+
algorithms: ["EdDSA", "X25519"],
|
|
116
|
+
severity: "low",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "paseto",
|
|
120
|
+
ecosystem: "npm",
|
|
121
|
+
reason: "PASETO public tokens signed with classical Ed25519 (v2/v4) or RSA.",
|
|
122
|
+
algorithms: ["EdDSA", "RSA"],
|
|
123
|
+
severity: "medium",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "bcrypto",
|
|
127
|
+
ecosystem: "npm",
|
|
128
|
+
reason: "Broad classical crypto suite: RSA, ECDSA, ECDH, Ed25519, DSA.",
|
|
129
|
+
algorithms: ["RSA", "ECDSA", "ECDH", "EdDSA", "DSA"],
|
|
130
|
+
severity: "high",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "ecpair",
|
|
134
|
+
ecosystem: "npm",
|
|
135
|
+
reason: "secp256k1 ECDSA key pairs for Bitcoin.",
|
|
136
|
+
algorithms: ["ECDSA"],
|
|
137
|
+
severity: "medium",
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "keypair",
|
|
141
|
+
ecosystem: "npm",
|
|
142
|
+
reason: "Pure-JS RSA key pair generation.",
|
|
143
|
+
algorithms: ["RSA"],
|
|
144
|
+
severity: "high",
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
/** Fast lookup map by package name. */
|
|
148
|
+
const BY_NAME = new Map(vulnerableDependencies.map((d) => [d.name, d]));
|
|
149
|
+
/**
|
|
150
|
+
* Precompiled `"name":` lookup regex per known package (P1-9): the package set
|
|
151
|
+
* is static, so we build the (escaped-name → RegExp) map once at module load
|
|
152
|
+
* rather than recompiling a fresh RegExp per found package per manifest.
|
|
153
|
+
*/
|
|
154
|
+
const KEY_REGEX_BY_NAME = new Map(vulnerableDependencies.map((d) => {
|
|
155
|
+
const escaped = d.name.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
156
|
+
return [d.name, new RegExp(`"${escaped}"\\s*:`)];
|
|
157
|
+
}));
|
|
158
|
+
/** Algorithm families that expose confidentiality (HNDL) rather than only signing. */
|
|
159
|
+
const CONFIDENTIALITY_FAMILIES = new Set([
|
|
160
|
+
"RSA",
|
|
161
|
+
"ECDH",
|
|
162
|
+
"DH",
|
|
163
|
+
"ECIES",
|
|
164
|
+
"X25519",
|
|
165
|
+
"X448",
|
|
166
|
+
]);
|
|
167
|
+
/**
|
|
168
|
+
* Build a remediation string covering ALL families a package exposes (C5),
|
|
169
|
+
* rather than only `algorithms[0]`. De-duplicates the per-family recommendation
|
|
170
|
+
* strings and joins them, so a signature+KEM library points at both replacements.
|
|
171
|
+
*/
|
|
172
|
+
function multiFamilyRemediation(algorithms) {
|
|
173
|
+
const parts = new Set();
|
|
174
|
+
for (const a of algorithms)
|
|
175
|
+
parts.add(remediationText(a));
|
|
176
|
+
return [...parts].join("; ");
|
|
177
|
+
}
|
|
178
|
+
/** True if a file path looks like a manifest we can parse for dependencies. */
|
|
179
|
+
export function isManifestFile(file) {
|
|
180
|
+
const base = file.split("/").pop() ?? file;
|
|
181
|
+
return base === "package.json" || base === "package-lock.json";
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Build a finding for a vulnerable dependency located in a manifest. The
|
|
185
|
+
* location points at the line where the package name appears in the file (best
|
|
186
|
+
* effort), falling back to line 1.
|
|
187
|
+
*/
|
|
188
|
+
function dependencyFinding(dep, file, content, index) {
|
|
189
|
+
// Use the first listed algorithm for the headline family, but derive the
|
|
190
|
+
// remediation from ALL families the package exposes (C5).
|
|
191
|
+
const algorithm = dep.algorithms[0] ?? "unknown";
|
|
192
|
+
return makeFinding({
|
|
193
|
+
ruleId: "dep-vulnerable",
|
|
194
|
+
title: `Quantum-vulnerable dependency: ${dep.name}`,
|
|
195
|
+
category: "dependency",
|
|
196
|
+
severity: dep.severity,
|
|
197
|
+
confidence: "high",
|
|
198
|
+
algorithm,
|
|
199
|
+
// Confidentiality libs are HNDL-exposed; signature-only ones are not.
|
|
200
|
+
hndl: dep.algorithms.some((a) => CONFIDENTIALITY_FAMILIES.has(a)),
|
|
201
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
202
|
+
message: `${dep.name} — ${dep.reason}`,
|
|
203
|
+
remediation: multiFamilyRemediation(dep.algorithms),
|
|
204
|
+
file,
|
|
205
|
+
content,
|
|
206
|
+
index,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/** Locate the offset of a JSON key `"name"` in the manifest text (or 0). */
|
|
210
|
+
function offsetOfKey(content, name) {
|
|
211
|
+
// Use the precompiled per-name regex (non-global; .exec from position 0).
|
|
212
|
+
const re = KEY_REGEX_BY_NAME.get(name);
|
|
213
|
+
if (!re)
|
|
214
|
+
return 0;
|
|
215
|
+
const m = re.exec(content);
|
|
216
|
+
return m ? m.index : 0;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Scan a single manifest file's contents for vulnerable dependencies.
|
|
220
|
+
*
|
|
221
|
+
* - `package.json`: dependencies / devDependencies / peerDependencies / optionalDependencies.
|
|
222
|
+
* - `package-lock.json` (v2/v3): the `packages` map keys (node_modules/<name>),
|
|
223
|
+
* plus legacy `dependencies` map for v1.
|
|
224
|
+
*
|
|
225
|
+
* Returns one finding per distinct vulnerable package name found in the file.
|
|
226
|
+
*/
|
|
227
|
+
export function scanManifest(file, content) {
|
|
228
|
+
let json;
|
|
229
|
+
try {
|
|
230
|
+
json = JSON.parse(content);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return []; // not valid JSON — skip quietly.
|
|
234
|
+
}
|
|
235
|
+
if (json === null || typeof json !== "object")
|
|
236
|
+
return [];
|
|
237
|
+
const found = new Set();
|
|
238
|
+
const obj = json;
|
|
239
|
+
const collectFromRecord = (rec) => {
|
|
240
|
+
if (rec === null || typeof rec !== "object")
|
|
241
|
+
return;
|
|
242
|
+
for (const key of Object.keys(rec)) {
|
|
243
|
+
if (BY_NAME.has(key))
|
|
244
|
+
found.add(key);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
// package.json dependency sections.
|
|
248
|
+
collectFromRecord(obj.dependencies);
|
|
249
|
+
collectFromRecord(obj.devDependencies);
|
|
250
|
+
collectFromRecord(obj.peerDependencies);
|
|
251
|
+
collectFromRecord(obj.optionalDependencies);
|
|
252
|
+
// package-lock.json v2/v3 "packages" map: keys are "node_modules/<name>".
|
|
253
|
+
const packages = obj.packages;
|
|
254
|
+
if (packages !== null && typeof packages === "object") {
|
|
255
|
+
for (const key of Object.keys(packages)) {
|
|
256
|
+
if (!key)
|
|
257
|
+
continue; // root package entry
|
|
258
|
+
const marker = "node_modules/";
|
|
259
|
+
const idx = key.lastIndexOf(marker);
|
|
260
|
+
const name = idx >= 0 ? key.slice(idx + marker.length) : key;
|
|
261
|
+
if (BY_NAME.has(name))
|
|
262
|
+
found.add(name);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const findings = [];
|
|
266
|
+
for (const name of found) {
|
|
267
|
+
const dep = BY_NAME.get(name);
|
|
268
|
+
if (!dep)
|
|
269
|
+
continue;
|
|
270
|
+
findings.push(dependencyFinding(dep, file, content, offsetOfKey(content, name)));
|
|
271
|
+
}
|
|
272
|
+
// Deterministic ordering by package name.
|
|
273
|
+
findings.sort((a, b) => (a.title < b.title ? -1 : a.title > b.title ? 1 : 0));
|
|
274
|
+
return findings;
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the regex-based source detectors: turning a string offset
|
|
3
|
+
* into a 1-based line/column, extracting a trimmed single-line snippet, and a
|
|
4
|
+
* small factory for building Finding objects with consistent remediation text.
|
|
5
|
+
*/
|
|
6
|
+
import type { AlgorithmFamily, Confidence, Finding, FindingCategory, Severity } from "./types.js";
|
|
7
|
+
/** A 1-based line/column position derived from a character offset. */
|
|
8
|
+
export interface LineCol {
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Convert a 0-based character offset within `content` into a 1-based
|
|
14
|
+
* line/column. Newlines are LF; CR is treated as an ordinary character, so on
|
|
15
|
+
* CRLF files the column includes the trailing CR offset harmlessly.
|
|
16
|
+
*/
|
|
17
|
+
export declare function offsetToLineCol(content: string, offset: number): LineCol;
|
|
18
|
+
/** Extract the (trimmed) single source line containing `offset`. */
|
|
19
|
+
export declare function lineAt(content: string, offset: number): string;
|
|
20
|
+
/** Inputs for {@link makeFinding}. */
|
|
21
|
+
export interface FindingSpec {
|
|
22
|
+
ruleId: string;
|
|
23
|
+
title: string;
|
|
24
|
+
category: FindingCategory;
|
|
25
|
+
severity: Severity;
|
|
26
|
+
confidence: Confidence;
|
|
27
|
+
algorithm?: AlgorithmFamily;
|
|
28
|
+
hndl: boolean;
|
|
29
|
+
message: string;
|
|
30
|
+
/** Override the auto-derived remediation text. */
|
|
31
|
+
remediation?: string;
|
|
32
|
+
/** Associated CWE id (e.g. "CWE-327"). */
|
|
33
|
+
cwe?: string;
|
|
34
|
+
/** The matched source text and its start offset within `content`. */
|
|
35
|
+
file: string;
|
|
36
|
+
content: string;
|
|
37
|
+
index: number;
|
|
38
|
+
/** Length of the match, used to compute endLine for multi-line matches. */
|
|
39
|
+
matchLength?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build a {@link Finding} with location info derived from a match offset. When
|
|
43
|
+
* no explicit remediation is given but an algorithm is, the canonical
|
|
44
|
+
* remediation text for that family is used.
|
|
45
|
+
*/
|
|
46
|
+
export declare function makeFinding(spec: FindingSpec): Finding;
|
|
47
|
+
/** True if `filePath` has one of the given (lower-case, dotted) extensions. */
|
|
48
|
+
export declare function hasExtension(filePath: string, exts: readonly string[]): boolean;
|
|
49
|
+
/** JavaScript / TypeScript source extensions handled by the source detectors. */
|
|
50
|
+
export declare const JS_TS_EXTENSIONS: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Given a SORTED ascending array of call offsets, return true when `idx` is at
|
|
53
|
+
* or after some call offset `c` with `idx - c < window`. Runs in O(log n) by
|
|
54
|
+
* binary-searching the largest call offset ≤ `idx` and checking the gap. This
|
|
55
|
+
* replaces the previous O(matches × calls) linear scan (`nearCall`).
|
|
56
|
+
*/
|
|
57
|
+
export declare function nearSortedCall(sortedCalls: readonly number[], idx: number, window: number): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Run a global regex over `content`, invoking `onMatch` for each hit. Resets
|
|
60
|
+
* lastIndex and guards against zero-width matches (which would loop forever).
|
|
61
|
+
*/
|
|
62
|
+
export declare function eachMatch(re: RegExp, content: string, onMatch: (match: RegExpExecArray) => void): void;
|
|
63
|
+
//# sourceMappingURL=detect-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-utils.d.ts","sourceRoot":"","sources":["../src/detect-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGlG,sEAAsE;AACtE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAUxE;AAED,oEAAoE;AACpE,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAkCtD;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAG/E;AAED,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAAmD,CAAC;AAElG;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAgBT;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GACxC,IAAI,CAQN"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { remediationText } from "./remediation.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert a 0-based character offset within `content` into a 1-based
|
|
4
|
+
* line/column. Newlines are LF; CR is treated as an ordinary character, so on
|
|
5
|
+
* CRLF files the column includes the trailing CR offset harmlessly.
|
|
6
|
+
*/
|
|
7
|
+
export function offsetToLineCol(content, offset) {
|
|
8
|
+
let line = 1;
|
|
9
|
+
let lastNewline = -1;
|
|
10
|
+
for (let i = 0; i < offset && i < content.length; i++) {
|
|
11
|
+
if (content.charCodeAt(i) === 10 /* \n */) {
|
|
12
|
+
line++;
|
|
13
|
+
lastNewline = i;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { line, column: offset - lastNewline };
|
|
17
|
+
}
|
|
18
|
+
/** Extract the (trimmed) single source line containing `offset`. */
|
|
19
|
+
export function lineAt(content, offset) {
|
|
20
|
+
let start = offset;
|
|
21
|
+
while (start > 0 && content.charCodeAt(start - 1) !== 10)
|
|
22
|
+
start--;
|
|
23
|
+
let end = offset;
|
|
24
|
+
while (end < content.length && content.charCodeAt(end) !== 10)
|
|
25
|
+
end++;
|
|
26
|
+
return content.slice(start, end).replace(/\r$/, "").trim();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a {@link Finding} with location info derived from a match offset. When
|
|
30
|
+
* no explicit remediation is given but an algorithm is, the canonical
|
|
31
|
+
* remediation text for that family is used.
|
|
32
|
+
*/
|
|
33
|
+
export function makeFinding(spec) {
|
|
34
|
+
const { line, column } = offsetToLineCol(spec.content, spec.index);
|
|
35
|
+
const snippet = lineAt(spec.content, spec.index);
|
|
36
|
+
const remediation = spec.remediation ?? (spec.algorithm ? remediationText(spec.algorithm) : undefined);
|
|
37
|
+
const location = {
|
|
38
|
+
file: spec.file,
|
|
39
|
+
line,
|
|
40
|
+
column,
|
|
41
|
+
snippet: snippet.length > 200 ? `${snippet.slice(0, 197)}...` : snippet,
|
|
42
|
+
};
|
|
43
|
+
if (spec.matchLength && spec.matchLength > 0) {
|
|
44
|
+
const matched = spec.content.slice(spec.index, spec.index + spec.matchLength);
|
|
45
|
+
const extraLines = (matched.match(/\n/g) ?? []).length;
|
|
46
|
+
if (extraLines > 0)
|
|
47
|
+
location.endLine = line + extraLines;
|
|
48
|
+
}
|
|
49
|
+
const finding = {
|
|
50
|
+
ruleId: spec.ruleId,
|
|
51
|
+
title: spec.title,
|
|
52
|
+
category: spec.category,
|
|
53
|
+
severity: spec.severity,
|
|
54
|
+
confidence: spec.confidence,
|
|
55
|
+
hndl: spec.hndl,
|
|
56
|
+
message: spec.message,
|
|
57
|
+
location,
|
|
58
|
+
};
|
|
59
|
+
if (spec.algorithm)
|
|
60
|
+
finding.algorithm = spec.algorithm;
|
|
61
|
+
if (remediation)
|
|
62
|
+
finding.remediation = remediation;
|
|
63
|
+
if (spec.cwe)
|
|
64
|
+
finding.cwe = spec.cwe;
|
|
65
|
+
return finding;
|
|
66
|
+
}
|
|
67
|
+
/** True if `filePath` has one of the given (lower-case, dotted) extensions. */
|
|
68
|
+
export function hasExtension(filePath, exts) {
|
|
69
|
+
const lower = filePath.toLowerCase();
|
|
70
|
+
return exts.some((e) => lower.endsWith(e));
|
|
71
|
+
}
|
|
72
|
+
/** JavaScript / TypeScript source extensions handled by the source detectors. */
|
|
73
|
+
export const JS_TS_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
74
|
+
/**
|
|
75
|
+
* Given a SORTED ascending array of call offsets, return true when `idx` is at
|
|
76
|
+
* or after some call offset `c` with `idx - c < window`. Runs in O(log n) by
|
|
77
|
+
* binary-searching the largest call offset ≤ `idx` and checking the gap. This
|
|
78
|
+
* replaces the previous O(matches × calls) linear scan (`nearCall`).
|
|
79
|
+
*/
|
|
80
|
+
export function nearSortedCall(sortedCalls, idx, window) {
|
|
81
|
+
// Find the rightmost element <= idx.
|
|
82
|
+
let lo = 0;
|
|
83
|
+
let hi = sortedCalls.length - 1;
|
|
84
|
+
let best = -1;
|
|
85
|
+
while (lo <= hi) {
|
|
86
|
+
const mid = (lo + hi) >>> 1;
|
|
87
|
+
if (sortedCalls[mid] <= idx) {
|
|
88
|
+
best = mid;
|
|
89
|
+
lo = mid + 1;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
hi = mid - 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (best < 0)
|
|
96
|
+
return false;
|
|
97
|
+
return idx - sortedCalls[best] < window;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Run a global regex over `content`, invoking `onMatch` for each hit. Resets
|
|
101
|
+
* lastIndex and guards against zero-width matches (which would loop forever).
|
|
102
|
+
*/
|
|
103
|
+
export function eachMatch(re, content, onMatch) {
|
|
104
|
+
const g = re.global ? re : new RegExp(re.source, `${re.flags}g`);
|
|
105
|
+
g.lastIndex = 0;
|
|
106
|
+
let m;
|
|
107
|
+
while ((m = g.exec(content)) !== null) {
|
|
108
|
+
onMatch(m);
|
|
109
|
+
if (m.index === g.lastIndex)
|
|
110
|
+
g.lastIndex++; // avoid infinite loop on empty match
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=detect-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-utils.js","sourceRoot":"","sources":["../src/detect-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config / certificate detector: finds PEM-encoded cryptographic material in
|
|
3
|
+
* any text file (source, config, .pem, .key, .crt, .env, …). This catches
|
|
4
|
+
* embedded private keys and X.509 certificates regardless of language.
|
|
5
|
+
*/
|
|
6
|
+
import type { Detector } from "../types.js";
|
|
7
|
+
/** Detects PEM key/certificate material in arbitrary files. */
|
|
8
|
+
export declare const pemDetector: Detector;
|
|
9
|
+
//# sourceMappingURL=pem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pem.d.ts","sourceRoot":"","sources":["../../src/detectors/pem.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,aAAa,CAAC;AAuHrD,+DAA+D;AAC/D,eAAO,MAAM,WAAW,EAAE,QAoCzB,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { eachMatch, makeFinding } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO, CWE_HARDCODED_KEY } from "../cwe.js";
|
|
3
|
+
const PEM_RULES = [
|
|
4
|
+
{
|
|
5
|
+
re: /-----BEGIN RSA PRIVATE KEY-----/g,
|
|
6
|
+
ruleId: "pem-rsa-private-key",
|
|
7
|
+
title: "RSA private key (PEM)",
|
|
8
|
+
category: "certificate",
|
|
9
|
+
severity: "critical",
|
|
10
|
+
algorithm: "RSA",
|
|
11
|
+
hndl: true,
|
|
12
|
+
cwe: CWE_HARDCODED_KEY,
|
|
13
|
+
message: "Embedded RSA private key (PKCS#1 PEM); classical and not quantum-safe.",
|
|
14
|
+
remediation: "Migrate to ML-DSA / ML-KEM keys and remove embedded private keys from source.",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
re: /-----BEGIN EC PRIVATE KEY-----/g,
|
|
18
|
+
ruleId: "pem-ec-private-key",
|
|
19
|
+
title: "EC private key (PEM)",
|
|
20
|
+
category: "certificate",
|
|
21
|
+
severity: "critical",
|
|
22
|
+
algorithm: "ECDSA",
|
|
23
|
+
hndl: true,
|
|
24
|
+
cwe: CWE_HARDCODED_KEY,
|
|
25
|
+
message: "Embedded EC private key (SEC1 PEM); classical ECDSA/ECDH key, not quantum-safe.",
|
|
26
|
+
remediation: "Migrate to ML-DSA (FIPS 204) keys and remove embedded private keys from source.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
re: /-----BEGIN DSA PRIVATE KEY-----/g,
|
|
30
|
+
ruleId: "pem-dsa-private-key",
|
|
31
|
+
title: "DSA private key (PEM)",
|
|
32
|
+
category: "certificate",
|
|
33
|
+
severity: "critical",
|
|
34
|
+
algorithm: "DSA",
|
|
35
|
+
hndl: false,
|
|
36
|
+
cwe: CWE_HARDCODED_KEY,
|
|
37
|
+
message: "Embedded DSA private key (PEM); classical, already deprecated, and not quantum-safe.",
|
|
38
|
+
remediation: "Rotate immediately (DSA is deprecated) and migrate to ML-DSA-65 (FIPS 204).",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
re: /-----BEGIN OPENSSH PRIVATE KEY-----/g,
|
|
42
|
+
ruleId: "pem-openssh-private-key",
|
|
43
|
+
title: "OpenSSH private key",
|
|
44
|
+
category: "certificate",
|
|
45
|
+
severity: "critical",
|
|
46
|
+
algorithm: "unknown",
|
|
47
|
+
hndl: true,
|
|
48
|
+
cwe: CWE_HARDCODED_KEY,
|
|
49
|
+
message: "Embedded OpenSSH private key (RSA/ECDSA/Ed25519); classical and not quantum-safe.",
|
|
50
|
+
remediation: "Rotate the key; plan migration to PQC-capable SSH (e.g. sntrup761x25519).",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
re: /-----BEGIN PGP PRIVATE KEY BLOCK-----/g,
|
|
54
|
+
ruleId: "pem-pgp-private-key",
|
|
55
|
+
title: "PGP/GPG private key block",
|
|
56
|
+
category: "certificate",
|
|
57
|
+
severity: "critical",
|
|
58
|
+
algorithm: "unknown",
|
|
59
|
+
hndl: true,
|
|
60
|
+
cwe: CWE_HARDCODED_KEY,
|
|
61
|
+
message: "Embedded PGP/GPG private key block (RSA/ECDSA/EdDSA/ElGamal); classical and not quantum-safe.",
|
|
62
|
+
remediation: "Rotate the key; track OpenPGP PQC drafts for migration.",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
re: /-----BEGIN PGP MESSAGE-----/g,
|
|
66
|
+
ruleId: "pem-pgp-message",
|
|
67
|
+
title: "PGP/GPG encrypted message",
|
|
68
|
+
category: "certificate",
|
|
69
|
+
severity: "low",
|
|
70
|
+
algorithm: "unknown",
|
|
71
|
+
hndl: true,
|
|
72
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
73
|
+
message: "Embedded PGP/GPG message; likely encrypted with classical RSA/ElGamal (harvest-now-decrypt-later).",
|
|
74
|
+
remediation: "Re-encrypt with PQC-capable tooling as OpenPGP PQC profiles mature.",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
re: /-----BEGIN (?:ENCRYPTED )?PRIVATE KEY-----/g,
|
|
78
|
+
ruleId: "pem-pkcs8-private-key",
|
|
79
|
+
title: "Private key (PKCS#8 PEM)",
|
|
80
|
+
category: "certificate",
|
|
81
|
+
severity: "critical",
|
|
82
|
+
algorithm: "unknown",
|
|
83
|
+
hndl: true,
|
|
84
|
+
cwe: CWE_HARDCODED_KEY,
|
|
85
|
+
message: "Embedded PKCS#8 private key; likely classical RSA/EC, not quantum-safe.",
|
|
86
|
+
remediation: "Migrate to PQC keys and remove embedded private keys from source.",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
re: /-----BEGIN CERTIFICATE-----/g,
|
|
90
|
+
ruleId: "pem-certificate",
|
|
91
|
+
title: "X.509 certificate (PEM)",
|
|
92
|
+
category: "certificate",
|
|
93
|
+
severity: "low",
|
|
94
|
+
algorithm: "unknown",
|
|
95
|
+
hndl: false,
|
|
96
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
97
|
+
message: "Embedded X.509 certificate; almost certainly signed with classical RSA/ECDSA.",
|
|
98
|
+
remediation: "Plan re-issuance with PQC-capable CAs as ML-DSA certificate profiles mature.",
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
/** Detects PEM key/certificate material in arbitrary files. */
|
|
102
|
+
export const pemDetector = {
|
|
103
|
+
id: "pem-material",
|
|
104
|
+
description: "PEM-encoded private keys and X.509 certificates in any file",
|
|
105
|
+
scope: "config",
|
|
106
|
+
language: "any",
|
|
107
|
+
// Applies to every text file; the walker already filters out binaries.
|
|
108
|
+
appliesTo: () => true,
|
|
109
|
+
detect({ file, content }) {
|
|
110
|
+
// Fast reject: only proceed if a PEM header is present at all.
|
|
111
|
+
if (!content.includes("-----BEGIN "))
|
|
112
|
+
return [];
|
|
113
|
+
const findings = [];
|
|
114
|
+
for (const rule of PEM_RULES) {
|
|
115
|
+
eachMatch(rule.re, content, (m) => {
|
|
116
|
+
findings.push(makeFinding({
|
|
117
|
+
ruleId: rule.ruleId,
|
|
118
|
+
title: rule.title,
|
|
119
|
+
category: rule.category,
|
|
120
|
+
severity: rule.severity,
|
|
121
|
+
confidence: "high",
|
|
122
|
+
algorithm: rule.algorithm,
|
|
123
|
+
hndl: rule.hndl,
|
|
124
|
+
cwe: rule.cwe,
|
|
125
|
+
message: rule.message,
|
|
126
|
+
remediation: rule.remediation,
|
|
127
|
+
file,
|
|
128
|
+
content,
|
|
129
|
+
index: m.index,
|
|
130
|
+
matchLength: m[0].length,
|
|
131
|
+
}));
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return findings;
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=pem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pem.js","sourceRoot":"","sources":["../../src/detectors/pem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source-code detectors for classical, non-quantum-safe asymmetric cryptography
|
|
3
|
+
* in JavaScript / TypeScript. Each detector is pure and stateless: it declares
|
|
4
|
+
* which files it applies to and returns zero or more Findings for a file's
|
|
5
|
+
* contents.
|
|
6
|
+
*
|
|
7
|
+
* The detection strategy is deliberately lexical (regex over source text). This
|
|
8
|
+
* is robust to bundling and partial files and keeps the package dependency-free.
|
|
9
|
+
* Confidence is set per-pattern to reflect how specific the match is.
|
|
10
|
+
*
|
|
11
|
+
* All per-file regexes are precompiled at module scope (not re-created per
|
|
12
|
+
* file) — `eachMatch` clones a fresh stateful copy only when a regex lacks the
|
|
13
|
+
* global flag, and these are all global, so they are reused safely.
|
|
14
|
+
*
|
|
15
|
+
* HNDL (harvest-now-decrypt-later) policy:
|
|
16
|
+
* - confidentiality primitives (key exchange / KEM: ECDH, DH, RSA-OAEP) → hndl:true
|
|
17
|
+
* - signatures (RSA-PSS, ECDSA, EdDSA, DSA, JWT alg) → hndl:false, but still high
|
|
18
|
+
* severity because a quantum attacker can forge them.
|
|
19
|
+
* - EC keygen is ambiguous (an 'ec' key feeds BOTH ECDSA and ECDH); it is
|
|
20
|
+
* classified conservatively as key-exchange-capable (hndl:true).
|
|
21
|
+
*/
|
|
22
|
+
import type { Detector } from "../types.js";
|
|
23
|
+
/** All built-in source/config detectors, in run order. */
|
|
24
|
+
export declare const sourceDetectors: Detector[];
|
|
25
|
+
//# sourceMappingURL=source.d.ts.map
|