@quantakrypto/core 0.4.2 → 0.4.4
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 +201 -0
- package/README.md +38 -10
- package/dist/agent-types.js.map +1 -1
- package/dist/baseline.js.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/cbom-merge.d.ts +9 -0
- package/dist/cbom-merge.d.ts.map +1 -0
- package/dist/cbom-merge.js +99 -0
- package/dist/cbom-merge.js.map +1 -0
- package/dist/cbom.js.map +1 -1
- package/dist/changed.js.map +1 -1
- package/dist/codemods/config-toggle.js.map +1 -1
- package/dist/codemods/registry.js.map +1 -1
- package/dist/comments.d.ts +29 -2
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +178 -18
- package/dist/comments.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/cwe.js.map +1 -1
- package/dist/dependencies.d.ts +3 -2
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +138 -2
- package/dist/dependencies.js.map +1 -1
- package/dist/detect-utils.d.ts +19 -4
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +43 -6
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/c.d.ts +4 -2
- package/dist/detectors/c.d.ts.map +1 -1
- package/dist/detectors/c.js +382 -3
- package/dist/detectors/c.js.map +1 -1
- package/dist/detectors/cicd.d.ts +27 -0
- package/dist/detectors/cicd.d.ts.map +1 -0
- package/dist/detectors/cicd.js +116 -0
- package/dist/detectors/cicd.js.map +1 -0
- package/dist/detectors/cloud-kms.d.ts +21 -0
- package/dist/detectors/cloud-kms.d.ts.map +1 -0
- package/dist/detectors/cloud-kms.js +57 -0
- package/dist/detectors/cloud-kms.js.map +1 -0
- package/dist/detectors/cloudformation.d.ts +30 -0
- package/dist/detectors/cloudformation.d.ts.map +1 -0
- package/dist/detectors/cloudformation.js +170 -0
- package/dist/detectors/cloudformation.js.map +1 -0
- package/dist/detectors/csharp.d.ts.map +1 -1
- package/dist/detectors/csharp.js +141 -3
- package/dist/detectors/csharp.js.map +1 -1
- package/dist/detectors/database.d.ts +17 -0
- package/dist/detectors/database.d.ts.map +1 -0
- package/dist/detectors/database.js +60 -0
- package/dist/detectors/database.js.map +1 -0
- package/dist/detectors/dnssec.d.ts +55 -0
- package/dist/detectors/dnssec.d.ts.map +1 -0
- package/dist/detectors/dnssec.js +107 -0
- package/dist/detectors/dnssec.js.map +1 -0
- package/dist/detectors/elixir.d.ts +20 -0
- package/dist/detectors/elixir.d.ts.map +1 -0
- package/dist/detectors/elixir.js +195 -0
- package/dist/detectors/elixir.js.map +1 -0
- package/dist/detectors/go.d.ts +5 -3
- package/dist/detectors/go.d.ts.map +1 -1
- package/dist/detectors/go.js +187 -3
- package/dist/detectors/go.js.map +1 -1
- package/dist/detectors/java.d.ts.map +1 -1
- package/dist/detectors/java.js +169 -4
- package/dist/detectors/java.js.map +1 -1
- package/dist/detectors/jose.d.ts +20 -0
- package/dist/detectors/jose.d.ts.map +1 -0
- package/dist/detectors/jose.js +62 -0
- package/dist/detectors/jose.js.map +1 -0
- package/dist/detectors/jwk.d.ts +25 -0
- package/dist/detectors/jwk.d.ts.map +1 -0
- package/dist/detectors/jwk.js +95 -0
- package/dist/detectors/jwk.js.map +1 -0
- package/dist/detectors/k8s.d.ts +17 -0
- package/dist/detectors/k8s.d.ts.map +1 -0
- package/dist/detectors/k8s.js +85 -0
- package/dist/detectors/k8s.js.map +1 -0
- package/dist/detectors/mesh.d.ts +35 -0
- package/dist/detectors/mesh.d.ts.map +1 -0
- package/dist/detectors/mesh.js +109 -0
- package/dist/detectors/mesh.js.map +1 -0
- package/dist/detectors/messaging.d.ts +16 -0
- package/dist/detectors/messaging.d.ts.map +1 -0
- package/dist/detectors/messaging.js +72 -0
- package/dist/detectors/messaging.js.map +1 -0
- package/dist/detectors/pem.d.ts.map +1 -1
- package/dist/detectors/pem.js +50 -2
- package/dist/detectors/pem.js.map +1 -1
- package/dist/detectors/php.d.ts +24 -0
- package/dist/detectors/php.d.ts.map +1 -0
- package/dist/detectors/php.js +167 -0
- package/dist/detectors/php.js.map +1 -0
- package/dist/detectors/python.d.ts.map +1 -1
- package/dist/detectors/python.js +144 -3
- package/dist/detectors/python.js.map +1 -1
- package/dist/detectors/ruby.d.ts +9 -5
- package/dist/detectors/ruby.d.ts.map +1 -1
- package/dist/detectors/ruby.js +122 -2
- package/dist/detectors/ruby.js.map +1 -1
- package/dist/detectors/rust.d.ts +8 -3
- package/dist/detectors/rust.d.ts.map +1 -1
- package/dist/detectors/rust.js +253 -3
- package/dist/detectors/rust.js.map +1 -1
- package/dist/detectors/secrets.d.ts +21 -0
- package/dist/detectors/secrets.d.ts.map +1 -0
- package/dist/detectors/secrets.js +79 -0
- package/dist/detectors/secrets.js.map +1 -0
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +305 -52
- package/dist/detectors/source.js.map +1 -1
- package/dist/detectors/stateful-hbs.d.ts +22 -0
- package/dist/detectors/stateful-hbs.d.ts.map +1 -0
- package/dist/detectors/stateful-hbs.js +142 -0
- package/dist/detectors/stateful-hbs.js.map +1 -0
- package/dist/detectors/terraform.d.ts +21 -0
- package/dist/detectors/terraform.d.ts.map +1 -0
- package/dist/detectors/terraform.js +123 -0
- package/dist/detectors/terraform.js.map +1 -0
- package/dist/detectors/vpn.d.ts +22 -0
- package/dist/detectors/vpn.d.ts.map +1 -0
- package/dist/detectors/vpn.js +99 -0
- package/dist/detectors/vpn.js.map +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/evidence.d.ts +53 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +81 -0
- package/dist/evidence.js.map +1 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +2 -0
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +27 -1
- package/dist/inventory.js.map +1 -1
- package/dist/parallel.js.map +1 -1
- package/dist/patch-policy.js.map +1 -1
- package/dist/policy.d.ts +67 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +115 -0
- package/dist/policy.js.map +1 -0
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +39 -0
- package/dist/redact.js.map +1 -1
- package/dist/registry.d.ts +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +34 -2
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +3 -0
- package/dist/remediate-pipeline.d.ts.map +1 -1
- package/dist/remediate-pipeline.js +71 -0
- package/dist/remediate-pipeline.js.map +1 -1
- package/dist/remediate-request.js.map +1 -1
- package/dist/remediation.d.ts +9 -3
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +17 -5
- package/dist/remediation.js.map +1 -1
- package/dist/report.d.ts +9 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +38 -0
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +8 -1
- package/dist/scan.js.map +1 -1
- package/dist/severity.js.map +1 -1
- package/dist/standards.d.ts +96 -0
- package/dist/standards.d.ts.map +1 -0
- package/dist/standards.js +107 -0
- package/dist/standards.js.map +1 -0
- package/dist/triage.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/walk.js.map +1 -1
- package/dist/worktree.js.map +1 -1
- package/package.json +1 -1
- package/src/cbom-merge.ts +116 -0
- package/src/comments.ts +183 -18
- package/src/dependencies.ts +144 -4
- package/src/detect-utils.ts +47 -6
- package/src/detectors/c.ts +411 -5
- package/src/detectors/cicd.ts +158 -0
- package/src/detectors/cloud-kms.ts +87 -0
- package/src/detectors/cloudformation.ts +215 -0
- package/src/detectors/csharp.ts +154 -3
- package/src/detectors/database.ts +88 -0
- package/src/detectors/dnssec.ts +186 -0
- package/src/detectors/elixir.ts +237 -0
- package/src/detectors/go.ts +209 -6
- package/src/detectors/java.ts +191 -4
- package/src/detectors/jose.ts +94 -0
- package/src/detectors/jwk.ts +128 -0
- package/src/detectors/k8s.ts +112 -0
- package/src/detectors/mesh.ts +154 -0
- package/src/detectors/messaging.ts +98 -0
- package/src/detectors/pem.ts +54 -2
- package/src/detectors/php.ts +225 -0
- package/src/detectors/python.ts +153 -3
- package/src/detectors/ruby.ts +138 -7
- package/src/detectors/rust.ts +282 -7
- package/src/detectors/secrets.ts +114 -0
- package/src/detectors/source.ts +382 -72
- package/src/detectors/stateful-hbs.ts +180 -0
- package/src/detectors/terraform.ts +154 -0
- package/src/detectors/vpn.ts +131 -0
- package/src/evidence.ts +135 -0
- package/src/index.ts +15 -1
- package/src/inventory.ts +31 -1
- package/src/policy.ts +180 -0
- package/src/redact.ts +41 -0
- package/src/registry.ts +34 -2
- package/src/remediate-pipeline.ts +78 -0
- package/src/remediation.ts +23 -8
- package/src/report.ts +48 -2
- package/src/scan.ts +13 -1
- package/src/standards.ts +186 -0
- package/src/types.ts +3 -1
- package/src/version.ts +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical KEY-MANAGEMENT (JWE) algorithms in JOSE. This is
|
|
3
|
+
* distinct from the JWS signature side (RS256/ES256, handled elsewhere) and from
|
|
4
|
+
* the JWK key-material detector: here we flag the `alg` values that wrap a
|
|
5
|
+
* content-encryption key with classical asymmetric crypto, because the encrypted
|
|
6
|
+
* payload is CONFIDENTIALITY — harvest-now-decrypt-later exposed. A JWE token
|
|
7
|
+
* captured today (from a log, an audit trail, a stored assertion) is decryptable
|
|
8
|
+
* once the wrapping key falls to a CRQC.
|
|
9
|
+
*
|
|
10
|
+
* Covered `alg` (RFC 7518 §4) values:
|
|
11
|
+
* - `RSA-OAEP`, `RSA-OAEP-256`, `RSA1_5` → RSA key encryption.
|
|
12
|
+
* - `ECDH-ES`, `ECDH-ES+A128KW`, … → classical EC Diffie-Hellman key agreement.
|
|
13
|
+
*
|
|
14
|
+
* These exact strings are JOSE identifiers, so a content-level match is precise;
|
|
15
|
+
* the detector applies to any file (config, JSON, source) after a fast reject.
|
|
16
|
+
*/
|
|
17
|
+
import type { Detector } from "../types.js";
|
|
18
|
+
/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */
|
|
19
|
+
export declare const joseDetector: Detector;
|
|
20
|
+
//# sourceMappingURL=jose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jose.d.ts","sourceRoot":"","sources":["../../src/detectors/jose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAgD/D,iFAAiF;AACjF,eAAO,MAAM,YAAY,EAAE,QA4B1B,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DOC_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
const JOSE_RULES = [
|
|
4
|
+
{
|
|
5
|
+
re: /"alg"\s*:\s*"RSA(?:-OAEP(?:-256)?|1_5)"/g,
|
|
6
|
+
meta: {
|
|
7
|
+
id: "jose-jwe-rsa",
|
|
8
|
+
title: "JWE RSA key wrapping",
|
|
9
|
+
description: 'JWE "alg" of RSA-OAEP / RSA-OAEP-256 / RSA1_5 (RFC 7518)',
|
|
10
|
+
category: "kem",
|
|
11
|
+
severity: "high",
|
|
12
|
+
confidence: "high",
|
|
13
|
+
algorithm: "RSA",
|
|
14
|
+
hndl: true,
|
|
15
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
16
|
+
message: "JWE wraps the content-encryption key with classical RSA (RSA-OAEP/RSA1_5); the encrypted payload is harvest-now-decrypt-later exposed.",
|
|
17
|
+
remediation: "Plan migration to a post-quantum KEM (ML-KEM-768) for key wrapping as JOSE/COSE PQ algorithms are standardised.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
re: /"alg"\s*:\s*"ECDH-ES(?:\+A\d{3}KW)?"/g,
|
|
22
|
+
meta: {
|
|
23
|
+
id: "jose-jwe-ecdh",
|
|
24
|
+
title: "JWE ECDH-ES key agreement",
|
|
25
|
+
description: 'JWE "alg" of ECDH-ES / ECDH-ES+A*KW (RFC 7518)',
|
|
26
|
+
category: "key-exchange",
|
|
27
|
+
severity: "high",
|
|
28
|
+
confidence: "high",
|
|
29
|
+
algorithm: "ECDH",
|
|
30
|
+
hndl: true,
|
|
31
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
32
|
+
message: "JWE derives the content-encryption key via classical ECDH-ES; the encrypted payload is harvest-now-decrypt-later exposed.",
|
|
33
|
+
remediation: "Plan migration to hybrid post-quantum key agreement (X25519MLKEM768) as JOSE PQ algorithms are standardised.",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */
|
|
38
|
+
export const joseDetector = {
|
|
39
|
+
id: "jose-jwe-keymgmt",
|
|
40
|
+
description: "Classical JWE key-management algorithms (RSA-OAEP, ECDH-ES) — confidentiality, HNDL",
|
|
41
|
+
scope: "config",
|
|
42
|
+
language: "any",
|
|
43
|
+
rules: JOSE_RULES.map((r) => r.meta),
|
|
44
|
+
// Prose examples (a README showing `"alg":"RSA-OAEP"`) are not JOSE config.
|
|
45
|
+
appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),
|
|
46
|
+
detect({ file, content }) {
|
|
47
|
+
// Fast reject: no JOSE key-management alg token present.
|
|
48
|
+
if (!content.includes("RSA-OAEP") &&
|
|
49
|
+
!content.includes("RSA1_5") &&
|
|
50
|
+
!content.includes("ECDH-ES")) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const findings = [];
|
|
54
|
+
for (const rule of JOSE_RULES) {
|
|
55
|
+
eachMatch(rule.re, content, (m) => {
|
|
56
|
+
findings.push(findingFromRule(rule.meta, { file, content, index: m.index, matchLength: m[0].length }));
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return findings;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=jose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jose.js","sourceRoot":"","sources":["../../src/detectors/jose.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAO9C,MAAM,UAAU,GAAe;IAC7B;QACE,EAAE,EAAE,0CAA0C;QAC9C,IAAI,EAAE;YACJ,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,sBAAsB;YAC7B,WAAW,EAAE,0DAA0D;YACvE,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,wIAAwI;YAC1I,WAAW,EACT,iHAAiH;SACpH;KACF;IACD;QACE,EAAE,EAAE,uCAAuC;QAC3C,IAAI,EAAE;YACJ,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,2BAA2B;YAClC,WAAW,EAAE,gDAAgD;YAC7D,QAAQ,EAAE,cAAc;YACxB,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,MAAM;YACjB,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,2HAA2H;YAC7H,WAAW,EACT,8GAA8G;SACjH;KACF;CACF,CAAC;AAEF,iFAAiF;AACjF,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,EAAE,EAAE,kBAAkB;IACtB,WAAW,EACT,qFAAqF;IACvF,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpC,4EAA4E;IAC5E,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc,CAAC;IAClD,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;QACtB,yDAAyD;QACzD,IACE,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC7B,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC3B,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAC5B,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBAChC,QAAQ,CAAC,IAAI,CACX,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CACxF,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC","sourcesContent":["/**\n * Config detector: classical KEY-MANAGEMENT (JWE) algorithms in JOSE. This is\n * distinct from the JWS signature side (RS256/ES256, handled elsewhere) and from\n * the JWK key-material detector: here we flag the `alg` values that wrap a\n * content-encryption key with classical asymmetric crypto, because the encrypted\n * payload is CONFIDENTIALITY — harvest-now-decrypt-later exposed. A JWE token\n * captured today (from a log, an audit trail, a stored assertion) is decryptable\n * once the wrapping key falls to a CRQC.\n *\n * Covered `alg` (RFC 7518 §4) values:\n * - `RSA-OAEP`, `RSA-OAEP-256`, `RSA1_5` → RSA key encryption.\n * - `ECDH-ES`, `ECDH-ES+A128KW`, … → classical EC Diffie-Hellman key agreement.\n *\n * These exact strings are JOSE identifiers, so a content-level match is precise;\n * the detector applies to any file (config, JSON, source) after a fast reject.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { DOC_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\ninterface JoseRule {\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst JOSE_RULES: JoseRule[] = [\n {\n re: /\"alg\"\\s*:\\s*\"RSA(?:-OAEP(?:-256)?|1_5)\"/g,\n meta: {\n id: \"jose-jwe-rsa\",\n title: \"JWE RSA key wrapping\",\n description: 'JWE \"alg\" of RSA-OAEP / RSA-OAEP-256 / RSA1_5 (RFC 7518)',\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JWE wraps the content-encryption key with classical RSA (RSA-OAEP/RSA1_5); the encrypted payload is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Plan migration to a post-quantum KEM (ML-KEM-768) for key wrapping as JOSE/COSE PQ algorithms are standardised.\",\n },\n },\n {\n re: /\"alg\"\\s*:\\s*\"ECDH-ES(?:\\+A\\d{3}KW)?\"/g,\n meta: {\n id: \"jose-jwe-ecdh\",\n title: \"JWE ECDH-ES key agreement\",\n description: 'JWE \"alg\" of ECDH-ES / ECDH-ES+A*KW (RFC 7518)',\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JWE derives the content-encryption key via classical ECDH-ES; the encrypted payload is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Plan migration to hybrid post-quantum key agreement (X25519MLKEM768) as JOSE PQ algorithms are standardised.\",\n },\n },\n];\n\n/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */\nexport const joseDetector: Detector = {\n id: \"jose-jwe-keymgmt\",\n description:\n \"Classical JWE key-management algorithms (RSA-OAEP, ECDH-ES) — confidentiality, HNDL\",\n scope: \"config\",\n language: \"any\",\n rules: JOSE_RULES.map((r) => r.meta),\n // Prose examples (a README showing `\"alg\":\"RSA-OAEP\"`) are not JOSE config.\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n // Fast reject: no JOSE key-management alg token present.\n if (\n !content.includes(\"RSA-OAEP\") &&\n !content.includes(\"RSA1_5\") &&\n !content.includes(\"ECDH-ES\")\n ) {\n return [];\n }\n const findings: Finding[] = [];\n for (const rule of JOSE_RULES) {\n eachMatch(rule.re, content, (m) => {\n findings.push(\n findingFromRule(rule.meta, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n }\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical key material in JSON Web Keys (JWK / JWKS, RFC 7517
|
|
3
|
+
* / 7518). JWKs appear in `.json` / `.jwks` files, OIDC discovery documents, and
|
|
4
|
+
* config — a real key-material surface the source packs (which look at *code*)
|
|
5
|
+
* and the PEM detector (which looks at PEM markers) both miss.
|
|
6
|
+
*
|
|
7
|
+
* Detection keys off the JWK's distinctive JSON fields:
|
|
8
|
+
* - `"kty":"RSA"` → classical RSA key.
|
|
9
|
+
* - `"crv":"P-256"|"P-384"|"P-521"|…` → classical EC key (ECDSA + ECDH).
|
|
10
|
+
* - `"crv":"Ed25519"|"Ed448"` → EdDSA signing key.
|
|
11
|
+
* - `"crv":"X25519"|"X448"` → classical Montgomery-curve key agreement.
|
|
12
|
+
*
|
|
13
|
+
* Keying EC/OKP off `crv` (present in every EC/OKP JWK) rather than `kty` avoids
|
|
14
|
+
* double-counting a single key, and `"kty"`/`"crv"` are specific enough to RFC
|
|
15
|
+
* 7517 that the false-positive risk on ordinary JSON is low.
|
|
16
|
+
*
|
|
17
|
+
* HNDL: RSA and (EC)DH / X25519 / X448 key agreement are harvest-now-decrypt-later
|
|
18
|
+
* exposed (hndl:true); EdDSA signing keys are hndl:false but forgeable. A JWKS is
|
|
19
|
+
* usually PUBLIC keys, so severity is medium — the exposure is a classical key
|
|
20
|
+
* pair, not necessarily an embedded secret.
|
|
21
|
+
*/
|
|
22
|
+
import type { Detector } from "../types.js";
|
|
23
|
+
/** Detects classical JSON Web Key (JWK/JWKS) material in any JSON/text file. */
|
|
24
|
+
export declare const jwkDetector: Detector;
|
|
25
|
+
//# sourceMappingURL=jwk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwk.d.ts","sourceRoot":"","sources":["../../src/detectors/jwk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAgF/D,gFAAgF;AAChF,eAAO,MAAM,WAAW,EAAE,QAyBzB,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { eachMatch, findingFromRule } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
const JWK_RULES = [
|
|
4
|
+
{
|
|
5
|
+
re: /"kty"\s*:\s*"RSA"/g,
|
|
6
|
+
meta: {
|
|
7
|
+
id: "jwk-rsa",
|
|
8
|
+
title: "RSA JSON Web Key (JWK)",
|
|
9
|
+
description: 'JWK with "kty":"RSA" (RFC 7518)',
|
|
10
|
+
category: "certificate",
|
|
11
|
+
severity: "medium",
|
|
12
|
+
confidence: "high",
|
|
13
|
+
algorithm: "RSA",
|
|
14
|
+
hndl: true,
|
|
15
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
16
|
+
message: "RSA JSON Web Key (JWK); classical RSA, not quantum-safe.",
|
|
17
|
+
remediation: "Re-issue with PQC keys (ML-KEM-768 for encryption, ML-DSA-65 for signatures).",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
re: /"crv"\s*:\s*"(?:P-256K?|P-384|P-521|secp256k1)"/g,
|
|
22
|
+
meta: {
|
|
23
|
+
id: "jwk-ec",
|
|
24
|
+
title: "EC JSON Web Key (JWK)",
|
|
25
|
+
description: 'JWK with an "crv" naming a NIST/secp curve (RFC 7518)',
|
|
26
|
+
category: "key-exchange",
|
|
27
|
+
severity: "medium",
|
|
28
|
+
confidence: "high",
|
|
29
|
+
algorithm: "ECDH",
|
|
30
|
+
hndl: true,
|
|
31
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
32
|
+
message: "Elliptic-curve JSON Web Key (JWK); a classical EC key feeds BOTH ECDSA signatures and ECDH key agreement — the ECDH path is harvest-now-decrypt-later exposed.",
|
|
33
|
+
remediation: "For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
re: /"crv"\s*:\s*"Ed(?:25519|448)"/g,
|
|
38
|
+
meta: {
|
|
39
|
+
id: "jwk-eddsa",
|
|
40
|
+
title: "EdDSA JSON Web Key (JWK)",
|
|
41
|
+
description: 'JWK OKP key with "crv":"Ed25519"/"Ed448" (RFC 8037)',
|
|
42
|
+
category: "signature",
|
|
43
|
+
severity: "low",
|
|
44
|
+
confidence: "high",
|
|
45
|
+
algorithm: "EdDSA",
|
|
46
|
+
hndl: false,
|
|
47
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
48
|
+
message: "EdDSA (Ed25519/Ed448) JSON Web Key (JWK); classical and forgeable by a quantum attacker.",
|
|
49
|
+
remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
re: /"crv"\s*:\s*"X(?:25519|448)"/g,
|
|
54
|
+
meta: {
|
|
55
|
+
id: "jwk-xdh",
|
|
56
|
+
title: "X25519/X448 JSON Web Key (JWK)",
|
|
57
|
+
description: 'JWK OKP key with "crv":"X25519"/"X448" (RFC 8037)',
|
|
58
|
+
category: "key-exchange",
|
|
59
|
+
severity: "medium",
|
|
60
|
+
confidence: "high",
|
|
61
|
+
algorithm: "X25519",
|
|
62
|
+
hndl: true,
|
|
63
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
64
|
+
message: "X25519/X448 JSON Web Key (JWK); modern but classical key agreement, and harvest-now-decrypt-later exposed.",
|
|
65
|
+
remediation: "Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
/** Detects classical JSON Web Key (JWK/JWKS) material in any JSON/text file. */
|
|
70
|
+
export const jwkDetector = {
|
|
71
|
+
id: "jwk-material",
|
|
72
|
+
description: "Classical key material in JSON Web Keys (JWK / JWKS)",
|
|
73
|
+
scope: "config",
|
|
74
|
+
language: "any",
|
|
75
|
+
rules: JWK_RULES.map((r) => r.meta),
|
|
76
|
+
appliesTo: () => true,
|
|
77
|
+
detect({ file, content }) {
|
|
78
|
+
// Fast reject: a JWK always has one of these two members.
|
|
79
|
+
if (!content.includes('"kty"') && !content.includes('"crv"'))
|
|
80
|
+
return [];
|
|
81
|
+
const findings = [];
|
|
82
|
+
for (const rule of JWK_RULES) {
|
|
83
|
+
eachMatch(rule.re, content, (m) => {
|
|
84
|
+
findings.push(findingFromRule(rule.meta, {
|
|
85
|
+
file,
|
|
86
|
+
content,
|
|
87
|
+
index: m.index,
|
|
88
|
+
matchLength: m[0].length,
|
|
89
|
+
}));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return findings;
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=jwk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwk.js","sourceRoot":"","sources":["../../src/detectors/jwk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical key material in JSON Web Keys (JWK / JWKS, RFC 7517\n * / 7518). JWKs appear in `.json` / `.jwks` files, OIDC discovery documents, and\n * config — a real key-material surface the source packs (which look at *code*)\n * and the PEM detector (which looks at PEM markers) both miss.\n *\n * Detection keys off the JWK's distinctive JSON fields:\n * - `\"kty\":\"RSA\"` → classical RSA key.\n * - `\"crv\":\"P-256\"|\"P-384\"|\"P-521\"|…` → classical EC key (ECDSA + ECDH).\n * - `\"crv\":\"Ed25519\"|\"Ed448\"` → EdDSA signing key.\n * - `\"crv\":\"X25519\"|\"X448\"` → classical Montgomery-curve key agreement.\n *\n * Keying EC/OKP off `crv` (present in every EC/OKP JWK) rather than `kty` avoids\n * double-counting a single key, and `\"kty\"`/`\"crv\"` are specific enough to RFC\n * 7517 that the false-positive risk on ordinary JSON is low.\n *\n * HNDL: RSA and (EC)DH / X25519 / X448 key agreement are harvest-now-decrypt-later\n * exposed (hndl:true); EdDSA signing keys are hndl:false but forgeable. A JWKS is\n * usually PUBLIC keys, so severity is medium — the exposure is a classical key\n * pair, not necessarily an embedded secret.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\ninterface JwkRule {\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst JWK_RULES: JwkRule[] = [\n {\n re: /\"kty\"\\s*:\\s*\"RSA\"/g,\n meta: {\n id: \"jwk-rsa\",\n title: \"RSA JSON Web Key (JWK)\",\n description: 'JWK with \"kty\":\"RSA\" (RFC 7518)',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"RSA JSON Web Key (JWK); classical RSA, not quantum-safe.\",\n remediation: \"Re-issue with PQC keys (ML-KEM-768 for encryption, ML-DSA-65 for signatures).\",\n },\n },\n {\n re: /\"crv\"\\s*:\\s*\"(?:P-256K?|P-384|P-521|secp256k1)\"/g,\n meta: {\n id: \"jwk-ec\",\n title: \"EC JSON Web Key (JWK)\",\n description: 'JWK with an \"crv\" naming a NIST/secp curve (RFC 7518)',\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Elliptic-curve JSON Web Key (JWK); a classical EC key feeds BOTH ECDSA signatures and ECDH key agreement — the ECDH path is harvest-now-decrypt-later exposed.\",\n remediation:\n \"For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).\",\n },\n },\n {\n re: /\"crv\"\\s*:\\s*\"Ed(?:25519|448)\"/g,\n meta: {\n id: \"jwk-eddsa\",\n title: \"EdDSA JSON Web Key (JWK)\",\n description: 'JWK OKP key with \"crv\":\"Ed25519\"/\"Ed448\" (RFC 8037)',\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"EdDSA (Ed25519/Ed448) JSON Web Key (JWK); classical and forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).\",\n },\n },\n {\n re: /\"crv\"\\s*:\\s*\"X(?:25519|448)\"/g,\n meta: {\n id: \"jwk-xdh\",\n title: \"X25519/X448 JSON Web Key (JWK)\",\n description: 'JWK OKP key with \"crv\":\"X25519\"/\"X448\" (RFC 8037)',\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519/X448 JSON Web Key (JWK); modern but classical key agreement, and harvest-now-decrypt-later exposed.\",\n remediation: \"Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).\",\n },\n },\n];\n\n/** Detects classical JSON Web Key (JWK/JWKS) material in any JSON/text file. */\nexport const jwkDetector: Detector = {\n id: \"jwk-material\",\n description: \"Classical key material in JSON Web Keys (JWK / JWKS)\",\n scope: \"config\",\n language: \"any\",\n rules: JWK_RULES.map((r) => r.meta),\n appliesTo: () => true,\n detect({ file, content }): Finding[] {\n // Fast reject: a JWK always has one of these two members.\n if (!content.includes('\"kty\"') && !content.includes('\"crv\"')) return [];\n const findings: Finding[] = [];\n for (const rule of JWK_RULES) {\n eachMatch(rule.re, content, (m) => {\n findings.push(\n findingFromRule(rule.meta, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n }\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical crypto in Kubernetes manifests — cert-manager key
|
|
3
|
+
* algorithms and service-mesh (Istio) TLS floors. These mint the certificates
|
|
4
|
+
* and secure the pod-to-pod traffic of a cluster, a surface neither the language
|
|
5
|
+
* packs nor the Terraform detector see.
|
|
6
|
+
*
|
|
7
|
+
* Covered (gated by a cert-manager / Istio marker in the document to keep the
|
|
8
|
+
* generic `algorithm:` / `minProtocolVersion:` keys from firing on unrelated YAML):
|
|
9
|
+
* - cert-manager `Certificate`/`Issuer` `privateKey.algorithm` (or legacy
|
|
10
|
+
* `keyAlgorithm`): `RSA` | `ECDSA` | `Ed25519`.
|
|
11
|
+
* - Istio `minProtocolVersion: TLSV1_0 | TLSV1_1` — a legacy TLS floor on mesh
|
|
12
|
+
* traffic, whose (EC)DHE key exchange is classical and harvestable.
|
|
13
|
+
*/
|
|
14
|
+
import type { Detector } from "../types.js";
|
|
15
|
+
/** Detects classical cert-manager keys and legacy Istio TLS floors in K8s YAML. */
|
|
16
|
+
export declare const k8sDetector: Detector;
|
|
17
|
+
//# sourceMappingURL=k8s.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"k8s.d.ts","sourceRoot":"","sources":["../../src/detectors/k8s.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAoE/D,mFAAmF;AACnF,eAAO,MAAM,WAAW,EAAE,QA6BzB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO, CWE_RISKY_PRIMITIVE } from "../cwe.js";
|
|
3
|
+
const K8S_EXTENSIONS = [".yaml", ".yml", ".json"];
|
|
4
|
+
const RE_CM_RSA = /(?:algorithm|keyAlgorithm):\s*["']?RSA\b/g;
|
|
5
|
+
const RE_CM_ECDSA = /(?:algorithm|keyAlgorithm):\s*["']?ECDSA\b/g;
|
|
6
|
+
const RE_CM_ED25519 = /(?:algorithm|keyAlgorithm):\s*["']?Ed25519\b/g;
|
|
7
|
+
const RE_ISTIO_LEGACY_TLS = /minProtocolVersion:\s*["']?TLSV1_[01]\b/g;
|
|
8
|
+
const RULE_CM_RSA = {
|
|
9
|
+
id: "k8s-certmanager-rsa",
|
|
10
|
+
title: "cert-manager RSA key",
|
|
11
|
+
description: "cert-manager Certificate/Issuer privateKey.algorithm = RSA",
|
|
12
|
+
category: "certificate",
|
|
13
|
+
severity: "medium",
|
|
14
|
+
confidence: "high",
|
|
15
|
+
algorithm: "RSA",
|
|
16
|
+
hndl: true,
|
|
17
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
18
|
+
message: "cert-manager mints certificates with a classical RSA key, which is not quantum-safe.",
|
|
19
|
+
remediation: "Plan migration to PQC certificate keys (ML-DSA-65) as the CA/issuer chain adds support.",
|
|
20
|
+
};
|
|
21
|
+
const RULE_CM_ECDSA = {
|
|
22
|
+
id: "k8s-certmanager-ecdsa",
|
|
23
|
+
title: "cert-manager ECDSA key",
|
|
24
|
+
description: "cert-manager Certificate/Issuer privateKey.algorithm = ECDSA",
|
|
25
|
+
category: "certificate",
|
|
26
|
+
severity: "medium",
|
|
27
|
+
confidence: "high",
|
|
28
|
+
algorithm: "ECDSA",
|
|
29
|
+
hndl: false,
|
|
30
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
31
|
+
message: "cert-manager mints certificates with a classical ECDSA key, forgeable by a quantum attacker.",
|
|
32
|
+
remediation: "Plan migration to ML-DSA-65 (FIPS 204) certificate keys.",
|
|
33
|
+
};
|
|
34
|
+
const RULE_CM_ED25519 = {
|
|
35
|
+
id: "k8s-certmanager-ed25519",
|
|
36
|
+
title: "cert-manager Ed25519 key",
|
|
37
|
+
description: "cert-manager Certificate/Issuer privateKey.algorithm = Ed25519",
|
|
38
|
+
category: "certificate",
|
|
39
|
+
severity: "low",
|
|
40
|
+
confidence: "high",
|
|
41
|
+
algorithm: "EdDSA",
|
|
42
|
+
hndl: false,
|
|
43
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
44
|
+
message: "cert-manager mints certificates with a classical Ed25519 key, forgeable by a quantum attacker.",
|
|
45
|
+
remediation: "Plan migration to ML-DSA-65 (FIPS 204) certificate keys.",
|
|
46
|
+
};
|
|
47
|
+
const RULE_ISTIO_LEGACY_TLS = {
|
|
48
|
+
id: "k8s-istio-legacy-tls",
|
|
49
|
+
title: "Istio legacy TLS floor",
|
|
50
|
+
description: "Istio minProtocolVersion allows TLS 1.0 / 1.1 on mesh traffic",
|
|
51
|
+
category: "tls",
|
|
52
|
+
severity: "medium",
|
|
53
|
+
confidence: "high",
|
|
54
|
+
hndl: false,
|
|
55
|
+
cwe: CWE_RISKY_PRIMITIVE,
|
|
56
|
+
message: "Istio mesh TLS floor allows TLS 1.0/1.1; its classical (EC)DHE key exchange is weak and harvestable.",
|
|
57
|
+
remediation: "Raise minProtocolVersion to TLSV1_3 and track PQC-hybrid mesh KEX (X25519MLKEM768).",
|
|
58
|
+
};
|
|
59
|
+
/** Detects classical cert-manager keys and legacy Istio TLS floors in K8s YAML. */
|
|
60
|
+
export const k8sDetector = {
|
|
61
|
+
id: "k8s-crypto",
|
|
62
|
+
description: "Classical crypto in Kubernetes manifests (cert-manager keys, Istio TLS floors)",
|
|
63
|
+
scope: "config",
|
|
64
|
+
language: "any",
|
|
65
|
+
rules: [RULE_CM_RSA, RULE_CM_ECDSA, RULE_CM_ED25519, RULE_ISTIO_LEGACY_TLS],
|
|
66
|
+
appliesTo: (f) => hasExtension(f, K8S_EXTENSIONS),
|
|
67
|
+
detect({ file, content }) {
|
|
68
|
+
const isCertManager = content.includes("cert-manager.io") ||
|
|
69
|
+
/kind:\s*["']?(?:Certificate|Issuer|ClusterIssuer)\b/.test(content);
|
|
70
|
+
const isIstio = content.includes("minProtocolVersion");
|
|
71
|
+
if (!isCertManager && !isIstio)
|
|
72
|
+
return [];
|
|
73
|
+
const findings = [];
|
|
74
|
+
const add = (re, rule) => eachMatch(re, content, (m) => findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length })));
|
|
75
|
+
if (isCertManager) {
|
|
76
|
+
add(RE_CM_RSA, RULE_CM_RSA);
|
|
77
|
+
add(RE_CM_ECDSA, RULE_CM_ECDSA);
|
|
78
|
+
add(RE_CM_ED25519, RULE_CM_ED25519);
|
|
79
|
+
}
|
|
80
|
+
if (isIstio)
|
|
81
|
+
add(RE_ISTIO_LEGACY_TLS, RULE_ISTIO_LEGACY_TLS);
|
|
82
|
+
return findings;
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=k8s.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"k8s.js","sourceRoot":"","sources":["../../src/detectors/k8s.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical crypto in Kubernetes manifests — cert-manager key\n * algorithms and service-mesh (Istio) TLS floors. These mint the certificates\n * and secure the pod-to-pod traffic of a cluster, a surface neither the language\n * packs nor the Terraform detector see.\n *\n * Covered (gated by a cert-manager / Istio marker in the document to keep the\n * generic `algorithm:` / `minProtocolVersion:` keys from firing on unrelated YAML):\n * - cert-manager `Certificate`/`Issuer` `privateKey.algorithm` (or legacy\n * `keyAlgorithm`): `RSA` | `ECDSA` | `Ed25519`.\n * - Istio `minProtocolVersion: TLSV1_0 | TLSV1_1` — a legacy TLS floor on mesh\n * traffic, whose (EC)DHE key exchange is classical and harvestable.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_RISKY_PRIMITIVE } from \"../cwe.js\";\n\nconst K8S_EXTENSIONS: readonly string[] = [\".yaml\", \".yml\", \".json\"];\n\nconst RE_CM_RSA = /(?:algorithm|keyAlgorithm):\\s*[\"']?RSA\\b/g;\nconst RE_CM_ECDSA = /(?:algorithm|keyAlgorithm):\\s*[\"']?ECDSA\\b/g;\nconst RE_CM_ED25519 = /(?:algorithm|keyAlgorithm):\\s*[\"']?Ed25519\\b/g;\nconst RE_ISTIO_LEGACY_TLS = /minProtocolVersion:\\s*[\"']?TLSV1_[01]\\b/g;\n\nconst RULE_CM_RSA: RuleMeta = {\n id: \"k8s-certmanager-rsa\",\n title: \"cert-manager RSA key\",\n description: \"cert-manager Certificate/Issuer privateKey.algorithm = RSA\",\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"cert-manager mints certificates with a classical RSA key, which is not quantum-safe.\",\n remediation:\n \"Plan migration to PQC certificate keys (ML-DSA-65) as the CA/issuer chain adds support.\",\n};\nconst RULE_CM_ECDSA: RuleMeta = {\n id: \"k8s-certmanager-ecdsa\",\n title: \"cert-manager ECDSA key\",\n description: \"cert-manager Certificate/Issuer privateKey.algorithm = ECDSA\",\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"cert-manager mints certificates with a classical ECDSA key, forgeable by a quantum attacker.\",\n remediation: \"Plan migration to ML-DSA-65 (FIPS 204) certificate keys.\",\n};\nconst RULE_CM_ED25519: RuleMeta = {\n id: \"k8s-certmanager-ed25519\",\n title: \"cert-manager Ed25519 key\",\n description: \"cert-manager Certificate/Issuer privateKey.algorithm = Ed25519\",\n category: \"certificate\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"cert-manager mints certificates with a classical Ed25519 key, forgeable by a quantum attacker.\",\n remediation: \"Plan migration to ML-DSA-65 (FIPS 204) certificate keys.\",\n};\nconst RULE_ISTIO_LEGACY_TLS: RuleMeta = {\n id: \"k8s-istio-legacy-tls\",\n title: \"Istio legacy TLS floor\",\n description: \"Istio minProtocolVersion allows TLS 1.0 / 1.1 on mesh traffic\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"Istio mesh TLS floor allows TLS 1.0/1.1; its classical (EC)DHE key exchange is weak and harvestable.\",\n remediation:\n \"Raise minProtocolVersion to TLSV1_3 and track PQC-hybrid mesh KEX (X25519MLKEM768).\",\n};\n\n/** Detects classical cert-manager keys and legacy Istio TLS floors in K8s YAML. */\nexport const k8sDetector: Detector = {\n id: \"k8s-crypto\",\n description: \"Classical crypto in Kubernetes manifests (cert-manager keys, Istio TLS floors)\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_CM_RSA, RULE_CM_ECDSA, RULE_CM_ED25519, RULE_ISTIO_LEGACY_TLS],\n appliesTo: (f) => hasExtension(f, K8S_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const isCertManager =\n content.includes(\"cert-manager.io\") ||\n /kind:\\s*[\"']?(?:Certificate|Issuer|ClusterIssuer)\\b/.test(content);\n const isIstio = content.includes(\"minProtocolVersion\");\n if (!isCertManager && !isIstio) return [];\n\n const findings: Finding[] = [];\n const add = (re: RegExp, rule: RuleMeta) =>\n eachMatch(re, content, (m) =>\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n if (isCertManager) {\n add(RE_CM_RSA, RULE_CM_RSA);\n add(RE_CM_ECDSA, RULE_CM_ECDSA);\n add(RE_CM_ED25519, RULE_CM_ED25519);\n }\n if (isIstio) add(RE_ISTIO_LEGACY_TLS, RULE_ISTIO_LEGACY_TLS);\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical crypto in SERVICE MESH configuration — the
|
|
3
|
+
* control-plane identity/CA systems and mesh-internal TLS settings of
|
|
4
|
+
* Linkerd, HashiCorp Consul Connect, and Istio. These mint the mTLS identity
|
|
5
|
+
* certificates that secure sidecar-to-sidecar traffic and are configured in
|
|
6
|
+
* their own Helm values / HCL / CRD surfaces, distinct from what `k8s.ts`
|
|
7
|
+
* already covers (cert-manager `Certificate`/`Issuer` keys and Istio's
|
|
8
|
+
* `minProtocolVersion` TLS floor — NOT duplicated here).
|
|
9
|
+
*
|
|
10
|
+
* Covered (gated by a mesh marker in the document to keep generic keys like
|
|
11
|
+
* `scheme:` / `private_key_type` from firing on unrelated YAML/HCL):
|
|
12
|
+
* - Linkerd control-plane identity issuer: Helm values `identityTrustAnchorsPEM`
|
|
13
|
+
* and `identity.issuer.scheme` / nested `issuer.scheme: linkerd.io/tls` — the
|
|
14
|
+
* default self-managed Linkerd identity scheme, which mints workload
|
|
15
|
+
* certificates from an ECDSA P-256 trust anchor. Flagged as a classical mesh
|
|
16
|
+
* CA (certificate, ECDSA, hndl:false) since Linkerd's identity issuer signs
|
|
17
|
+
* forgeable-by-quantum leaf certs, not a confidentiality key.
|
|
18
|
+
* - HashiCorp Consul Connect: the `connect { ca_config { private_key_type =
|
|
19
|
+
* "ec" | "rsa" } } }` mesh CA provider setting (also `ca_provider`). Flagged
|
|
20
|
+
* as a classical mesh CA (certificate; ECDSA for "ec", RSA for "rsa").
|
|
21
|
+
* - Istio `DestinationRule` / `Gateway` `tls.cipherSuites:` listing a classical
|
|
22
|
+
* `ECDHE-RSA-*` / `ECDHE-ECDSA-*` suite — the (EC)DHE key exchange in these
|
|
23
|
+
* suites is classical and harvest-now-decrypt-later exposed (tls, ECDH,
|
|
24
|
+
* hndl:true). This complements, and does not duplicate, `k8s.ts`'s
|
|
25
|
+
* `minProtocolVersion` legacy-TLS-floor rule.
|
|
26
|
+
*/
|
|
27
|
+
import type { Detector } from "../types.js";
|
|
28
|
+
/**
|
|
29
|
+
* Detects classical asymmetric crypto in service-mesh configuration: Linkerd's
|
|
30
|
+
* default ECDSA identity issuer, Consul Connect's mesh CA private key type,
|
|
31
|
+
* and classical ECDHE cipher suites in Istio DestinationRule/Gateway TLS
|
|
32
|
+
* policy.
|
|
33
|
+
*/
|
|
34
|
+
export declare const meshDetector: Detector;
|
|
35
|
+
//# sourceMappingURL=mesh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh.d.ts","sourceRoot":"","sources":["../../src/detectors/mesh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAuF/D;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,QAkC1B,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO, CWE_RISKY_PRIMITIVE } from "../cwe.js";
|
|
3
|
+
const MESH_EXTENSIONS = [".yaml", ".yml", ".hcl"];
|
|
4
|
+
// Linkerd's default self-managed identity scheme (`linkerd.io/tls`, as opposed
|
|
5
|
+
// to a `kubernetes.io/tls` bring-your-own-cert secret) mints its trust anchor
|
|
6
|
+
// and issuer credentials as ECDSA P-256 by default. Matched in both nested
|
|
7
|
+
// YAML form (`scheme: linkerd.io/tls`) and the flattened Helm `--set`/values
|
|
8
|
+
// key form (`identity.issuer.scheme: linkerd.io/tls`), plus the distinctive
|
|
9
|
+
// `identityTrustAnchorsPEM` values key which only exists in Linkerd charts.
|
|
10
|
+
const RE_MESH_LINKERD_ECDSA = /identityTrustAnchorsPEM\b|(?:identity\.issuer\.scheme|scheme)\s*[:=]\s*["']?linkerd\.io\/tls\b/g;
|
|
11
|
+
// Consul Connect's CA provider config: `private_key_type = "ec" | "rsa"`
|
|
12
|
+
// inside a `ca_config` block. Matched in both HCL (`=`) and JSON (`:`) forms,
|
|
13
|
+
// mirroring the terraform.ts attribute-matching convention.
|
|
14
|
+
const RE_MESH_CONSUL_RSA = /(?<![\w"-])"?private_key_type"?\s*[:=]\s*"rsa"/gi;
|
|
15
|
+
const RE_MESH_CONSUL_EC = /(?<![\w"-])"?private_key_type"?\s*[:=]\s*"ec"/gi;
|
|
16
|
+
// Istio mesh TLS cipher suites: OpenSSL-style suite names naming classical
|
|
17
|
+
// ECDHE key exchange combined with an RSA or ECDSA certificate. These are
|
|
18
|
+
// distinctive tokens (no generic-config collision risk).
|
|
19
|
+
const RE_MESH_ISTIO_CLASSICAL_CIPHER = /\bECDHE-(?:RSA|ECDSA)-[A-Z0-9_-]+\b/g;
|
|
20
|
+
const RULE_MESH_LINKERD_ECDSA = {
|
|
21
|
+
id: "mesh-linkerd-identity-ecdsa",
|
|
22
|
+
title: "Linkerd ECDSA identity issuer",
|
|
23
|
+
description: "Linkerd control-plane identity issuer (default ECDSA P-256 mesh CA)",
|
|
24
|
+
category: "certificate",
|
|
25
|
+
severity: "medium",
|
|
26
|
+
confidence: "high",
|
|
27
|
+
algorithm: "ECDSA",
|
|
28
|
+
hndl: false,
|
|
29
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
30
|
+
message: "Linkerd's control-plane identity issuer mints workload certificates from a classical ECDSA P-256 trust anchor by default, forgeable by a quantum attacker.",
|
|
31
|
+
remediation: "Plan migration to ML-DSA-65 (FIPS 204) once Linkerd's identity issuer supports PQC signing.",
|
|
32
|
+
};
|
|
33
|
+
const RULE_MESH_CONSUL_RSA = {
|
|
34
|
+
id: "mesh-consul-connect-rsa",
|
|
35
|
+
title: "Consul Connect RSA mesh CA",
|
|
36
|
+
description: 'Consul Connect ca_config private_key_type = "rsa"',
|
|
37
|
+
category: "certificate",
|
|
38
|
+
severity: "medium",
|
|
39
|
+
confidence: "high",
|
|
40
|
+
algorithm: "RSA",
|
|
41
|
+
hndl: true,
|
|
42
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
43
|
+
message: "Consul Connect's mesh CA issues leaf certificates from a classical RSA private key, which is not quantum-safe.",
|
|
44
|
+
remediation: "Plan migration to PQC certificate keys (ML-DSA-65) as the Connect CA provider adds support.",
|
|
45
|
+
};
|
|
46
|
+
const RULE_MESH_CONSUL_EC = {
|
|
47
|
+
id: "mesh-consul-connect-ec",
|
|
48
|
+
title: "Consul Connect EC mesh CA",
|
|
49
|
+
description: 'Consul Connect ca_config private_key_type = "ec"',
|
|
50
|
+
category: "certificate",
|
|
51
|
+
severity: "medium",
|
|
52
|
+
confidence: "high",
|
|
53
|
+
algorithm: "ECDSA",
|
|
54
|
+
hndl: false,
|
|
55
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
56
|
+
message: "Consul Connect's mesh CA issues leaf certificates from a classical EC private key, forgeable by a quantum attacker.",
|
|
57
|
+
remediation: "Plan migration to ML-DSA-65 (FIPS 204) as the Connect CA provider adds support.",
|
|
58
|
+
};
|
|
59
|
+
const RULE_MESH_ISTIO_CLASSICAL_CIPHER = {
|
|
60
|
+
id: "mesh-istio-classical-cipher",
|
|
61
|
+
title: "Istio classical ECDHE cipher suite",
|
|
62
|
+
description: "Istio DestinationRule/Gateway tls.cipherSuites lists a classical ECDHE-RSA/ECDHE-ECDSA suite",
|
|
63
|
+
category: "tls",
|
|
64
|
+
severity: "medium",
|
|
65
|
+
confidence: "high",
|
|
66
|
+
algorithm: "ECDH",
|
|
67
|
+
hndl: true,
|
|
68
|
+
cwe: CWE_RISKY_PRIMITIVE,
|
|
69
|
+
message: "Istio mesh TLS cipher suite allows classical ECDHE key exchange, which is harvest-now-decrypt-later exposed.",
|
|
70
|
+
remediation: "Prefer TLS 1.3 AEAD suites and track PQC-hybrid mesh key exchange (X25519MLKEM768) as Envoy/BoringSSL adds support.",
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Detects classical asymmetric crypto in service-mesh configuration: Linkerd's
|
|
74
|
+
* default ECDSA identity issuer, Consul Connect's mesh CA private key type,
|
|
75
|
+
* and classical ECDHE cipher suites in Istio DestinationRule/Gateway TLS
|
|
76
|
+
* policy.
|
|
77
|
+
*/
|
|
78
|
+
export const meshDetector = {
|
|
79
|
+
id: "service-mesh-crypto",
|
|
80
|
+
description: "Classical crypto in service-mesh config (Linkerd identity, Consul Connect CA, Istio cipher suites)",
|
|
81
|
+
scope: "config",
|
|
82
|
+
language: "any",
|
|
83
|
+
rules: [
|
|
84
|
+
RULE_MESH_LINKERD_ECDSA,
|
|
85
|
+
RULE_MESH_CONSUL_RSA,
|
|
86
|
+
RULE_MESH_CONSUL_EC,
|
|
87
|
+
RULE_MESH_ISTIO_CLASSICAL_CIPHER,
|
|
88
|
+
],
|
|
89
|
+
appliesTo: (f) => hasExtension(f, MESH_EXTENSIONS),
|
|
90
|
+
detect({ file, content }) {
|
|
91
|
+
const isLinkerd = content.includes("linkerd") || content.includes("identityTrustAnchors");
|
|
92
|
+
const isConsulConnect = content.includes("consul") && content.includes("connect");
|
|
93
|
+
const isIstioCipher = content.includes("DestinationRule") || content.includes("cipherSuites");
|
|
94
|
+
if (!isLinkerd && !isConsulConnect && !isIstioCipher)
|
|
95
|
+
return [];
|
|
96
|
+
const findings = [];
|
|
97
|
+
const add = (re, rule) => eachMatch(re, content, (m) => findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length })));
|
|
98
|
+
if (isLinkerd)
|
|
99
|
+
add(RE_MESH_LINKERD_ECDSA, RULE_MESH_LINKERD_ECDSA);
|
|
100
|
+
if (isConsulConnect) {
|
|
101
|
+
add(RE_MESH_CONSUL_RSA, RULE_MESH_CONSUL_RSA);
|
|
102
|
+
add(RE_MESH_CONSUL_EC, RULE_MESH_CONSUL_EC);
|
|
103
|
+
}
|
|
104
|
+
if (isIstioCipher)
|
|
105
|
+
add(RE_MESH_ISTIO_CLASSICAL_CIPHER, RULE_MESH_ISTIO_CLASSICAL_CIPHER);
|
|
106
|
+
return findings;
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=mesh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh.js","sourceRoot":"","sources":["../../src/detectors/mesh.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical crypto in SERVICE MESH configuration — the\n * control-plane identity/CA systems and mesh-internal TLS settings of\n * Linkerd, HashiCorp Consul Connect, and Istio. These mint the mTLS identity\n * certificates that secure sidecar-to-sidecar traffic and are configured in\n * their own Helm values / HCL / CRD surfaces, distinct from what `k8s.ts`\n * already covers (cert-manager `Certificate`/`Issuer` keys and Istio's\n * `minProtocolVersion` TLS floor — NOT duplicated here).\n *\n * Covered (gated by a mesh marker in the document to keep generic keys like\n * `scheme:` / `private_key_type` from firing on unrelated YAML/HCL):\n * - Linkerd control-plane identity issuer: Helm values `identityTrustAnchorsPEM`\n * and `identity.issuer.scheme` / nested `issuer.scheme: linkerd.io/tls` — the\n * default self-managed Linkerd identity scheme, which mints workload\n * certificates from an ECDSA P-256 trust anchor. Flagged as a classical mesh\n * CA (certificate, ECDSA, hndl:false) since Linkerd's identity issuer signs\n * forgeable-by-quantum leaf certs, not a confidentiality key.\n * - HashiCorp Consul Connect: the `connect { ca_config { private_key_type =\n * \"ec\" | \"rsa\" } } }` mesh CA provider setting (also `ca_provider`). Flagged\n * as a classical mesh CA (certificate; ECDSA for \"ec\", RSA for \"rsa\").\n * - Istio `DestinationRule` / `Gateway` `tls.cipherSuites:` listing a classical\n * `ECDHE-RSA-*` / `ECDHE-ECDSA-*` suite — the (EC)DHE key exchange in these\n * suites is classical and harvest-now-decrypt-later exposed (tls, ECDH,\n * hndl:true). This complements, and does not duplicate, `k8s.ts`'s\n * `minProtocolVersion` legacy-TLS-floor rule.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_RISKY_PRIMITIVE } from \"../cwe.js\";\n\nconst MESH_EXTENSIONS: readonly string[] = [\".yaml\", \".yml\", \".hcl\"];\n\n// Linkerd's default self-managed identity scheme (`linkerd.io/tls`, as opposed\n// to a `kubernetes.io/tls` bring-your-own-cert secret) mints its trust anchor\n// and issuer credentials as ECDSA P-256 by default. Matched in both nested\n// YAML form (`scheme: linkerd.io/tls`) and the flattened Helm `--set`/values\n// key form (`identity.issuer.scheme: linkerd.io/tls`), plus the distinctive\n// `identityTrustAnchorsPEM` values key which only exists in Linkerd charts.\nconst RE_MESH_LINKERD_ECDSA =\n /identityTrustAnchorsPEM\\b|(?:identity\\.issuer\\.scheme|scheme)\\s*[:=]\\s*[\"']?linkerd\\.io\\/tls\\b/g;\n\n// Consul Connect's CA provider config: `private_key_type = \"ec\" | \"rsa\"`\n// inside a `ca_config` block. Matched in both HCL (`=`) and JSON (`:`) forms,\n// mirroring the terraform.ts attribute-matching convention.\nconst RE_MESH_CONSUL_RSA = /(?<![\\w\"-])\"?private_key_type\"?\\s*[:=]\\s*\"rsa\"/gi;\nconst RE_MESH_CONSUL_EC = /(?<![\\w\"-])\"?private_key_type\"?\\s*[:=]\\s*\"ec\"/gi;\n\n// Istio mesh TLS cipher suites: OpenSSL-style suite names naming classical\n// ECDHE key exchange combined with an RSA or ECDSA certificate. These are\n// distinctive tokens (no generic-config collision risk).\nconst RE_MESH_ISTIO_CLASSICAL_CIPHER = /\\bECDHE-(?:RSA|ECDSA)-[A-Z0-9_-]+\\b/g;\n\nconst RULE_MESH_LINKERD_ECDSA: RuleMeta = {\n id: \"mesh-linkerd-identity-ecdsa\",\n title: \"Linkerd ECDSA identity issuer\",\n description: \"Linkerd control-plane identity issuer (default ECDSA P-256 mesh CA)\",\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Linkerd's control-plane identity issuer mints workload certificates from a classical ECDSA P-256 trust anchor by default, forgeable by a quantum attacker.\",\n remediation:\n \"Plan migration to ML-DSA-65 (FIPS 204) once Linkerd's identity issuer supports PQC signing.\",\n};\nconst RULE_MESH_CONSUL_RSA: RuleMeta = {\n id: \"mesh-consul-connect-rsa\",\n title: \"Consul Connect RSA mesh CA\",\n description: 'Consul Connect ca_config private_key_type = \"rsa\"',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Consul Connect's mesh CA issues leaf certificates from a classical RSA private key, which is not quantum-safe.\",\n remediation:\n \"Plan migration to PQC certificate keys (ML-DSA-65) as the Connect CA provider adds support.\",\n};\nconst RULE_MESH_CONSUL_EC: RuleMeta = {\n id: \"mesh-consul-connect-ec\",\n title: \"Consul Connect EC mesh CA\",\n description: 'Consul Connect ca_config private_key_type = \"ec\"',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Consul Connect's mesh CA issues leaf certificates from a classical EC private key, forgeable by a quantum attacker.\",\n remediation: \"Plan migration to ML-DSA-65 (FIPS 204) as the Connect CA provider adds support.\",\n};\nconst RULE_MESH_ISTIO_CLASSICAL_CIPHER: RuleMeta = {\n id: \"mesh-istio-classical-cipher\",\n title: \"Istio classical ECDHE cipher suite\",\n description:\n \"Istio DestinationRule/Gateway tls.cipherSuites lists a classical ECDHE-RSA/ECDHE-ECDSA suite\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"Istio mesh TLS cipher suite allows classical ECDHE key exchange, which is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Prefer TLS 1.3 AEAD suites and track PQC-hybrid mesh key exchange (X25519MLKEM768) as Envoy/BoringSSL adds support.\",\n};\n\n/**\n * Detects classical asymmetric crypto in service-mesh configuration: Linkerd's\n * default ECDSA identity issuer, Consul Connect's mesh CA private key type,\n * and classical ECDHE cipher suites in Istio DestinationRule/Gateway TLS\n * policy.\n */\nexport const meshDetector: Detector = {\n id: \"service-mesh-crypto\",\n description:\n \"Classical crypto in service-mesh config (Linkerd identity, Consul Connect CA, Istio cipher suites)\",\n scope: \"config\",\n language: \"any\",\n rules: [\n RULE_MESH_LINKERD_ECDSA,\n RULE_MESH_CONSUL_RSA,\n RULE_MESH_CONSUL_EC,\n RULE_MESH_ISTIO_CLASSICAL_CIPHER,\n ],\n appliesTo: (f) => hasExtension(f, MESH_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const isLinkerd = content.includes(\"linkerd\") || content.includes(\"identityTrustAnchors\");\n const isConsulConnect = content.includes(\"consul\") && content.includes(\"connect\");\n const isIstioCipher = content.includes(\"DestinationRule\") || content.includes(\"cipherSuites\");\n if (!isLinkerd && !isConsulConnect && !isIstioCipher) return [];\n\n const findings: Finding[] = [];\n const add = (re: RegExp, rule: RuleMeta) =>\n eachMatch(re, content, (m) =>\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n if (isLinkerd) add(RE_MESH_LINKERD_ECDSA, RULE_MESH_LINKERD_ECDSA);\n if (isConsulConnect) {\n add(RE_MESH_CONSUL_RSA, RULE_MESH_CONSUL_RSA);\n add(RE_MESH_CONSUL_EC, RULE_MESH_CONSUL_EC);\n }\n if (isIstioCipher) add(RE_MESH_ISTIO_CLASSICAL_CIPHER, RULE_MESH_ISTIO_CLASSICAL_CIPHER);\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical transport crypto in message brokers / event streams
|
|
3
|
+
* (Kafka, RabbitMQ, MQTT/Mosquitto, NATS). Broker traffic is "communication
|
|
4
|
+
* between things"; a legacy TLS floor or a classical (EC)DHE cipher suite makes
|
|
5
|
+
* every message in flight harvest-now-decrypt-later exposed.
|
|
6
|
+
*
|
|
7
|
+
* Covered in broker config files (`.properties`, `.conf`, `.cfg`, `.ini`):
|
|
8
|
+
* - Kafka `ssl.protocol` / `ssl.enabled.protocols = TLSv1 | TLSv1.1` (legacy).
|
|
9
|
+
* - MQTT/Mosquitto `tls_version tlsv1 | tlsv1.1` (legacy).
|
|
10
|
+
* - Kafka `ssl.cipher.suites` naming a classical `ECDHE_RSA` / `ECDHE_ECDSA` /
|
|
11
|
+
* `TLS_RSA` suite — the harvestable key-exchange path.
|
|
12
|
+
*/
|
|
13
|
+
import type { Detector } from "../types.js";
|
|
14
|
+
/** Detects classical transport crypto in message-broker / event-stream config. */
|
|
15
|
+
export declare const messagingDetector: Detector;
|
|
16
|
+
//# sourceMappingURL=messaging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../../src/detectors/messaging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAkE/D,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,EAAE,QAkB/B,CAAC"}
|