@blamejs/exceptd-skills 0.12.15 → 0.12.18

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.
@@ -67,7 +67,9 @@
67
67
  "T1552.001",
68
68
  "T1555"
69
69
  ],
70
- "cve_refs": [],
70
+ "cve_refs": [
71
+ "CVE-2026-30615"
72
+ ],
71
73
  "cwe_refs": [
72
74
  "CWE-522",
73
75
  "CWE-256",
@@ -472,7 +474,12 @@
472
474
  "description": "Primary credential-exposure indicator. Userland code execution → key extraction in milliseconds.",
473
475
  "confidence": "deterministic",
474
476
  "deterministic": true,
475
- "attack_ref": "T1552.001"
477
+ "attack_ref": "T1552.001",
478
+ "false_positive_checks_required": [
479
+ "Decode the key prefix — sk-test-*, sk_test_*, anthropic-test-*, hf_dummy_* and similar documented placeholder formats are SDK quickstart fixtures; demote to miss.",
480
+ "If the dotfile is under examples/, tests/, fixtures/, docs/, sdk-quickstart/ or a vendor's reference-repo path, treat as documentation; demote to miss unless the key validates against the vendor's live API.",
481
+ "Verify the key length meets the format's minimum entropy floor (real OpenAI sk-* >=48 chars after prefix; Anthropic sk-ant-* >=40 chars; Google AIza* >=39 chars). Below the floor is a placeholder; demote."
482
+ ]
476
483
  },
477
484
  {
478
485
  "id": "long-lived-aws-keys",
@@ -481,7 +488,12 @@
481
488
  "description": "Long-lived AWS keys in dotfile — high-value target.",
482
489
  "confidence": "deterministic",
483
490
  "deterministic": true,
484
- "attack_ref": "T1552.001"
491
+ "attack_ref": "T1552.001",
492
+ "false_positive_checks_required": [
493
+ "If the access-key prefix is AKIAIOSFODNN7EXAMPLE / wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY or any other documented AWS sample credential pair, demote to miss — these are AWS-published doc fixtures.",
494
+ "Verify the credentials file resides under examples/, tests/, fixtures/, or a documented vendor-reference path before flagging; demote when so.",
495
+ "Cross-check via aws sts get-caller-identity (or equivalent dry-run) — if the key is already deactivated/deleted at the vendor side it is a stale revoked credential, demote to lower confidence."
496
+ ]
485
497
  },
486
498
  {
487
499
  "id": "gcp-service-account-json",
@@ -490,7 +502,12 @@
490
502
  "description": "Service-account JSON key (long-lived) in user dotfile — known anti-pattern.",
491
503
  "confidence": "deterministic",
492
504
  "deterministic": true,
493
- "attack_ref": "T1552.001"
505
+ "attack_ref": "T1552.001",
506
+ "false_positive_checks_required": [
507
+ "If the private_key field is the literal value 'PLACEHOLDER' / 'REDACTED' / a PEM body of fewer than 1000 chars, the file is a stub; demote to miss.",
508
+ "Verify the client_email domain — *@gserviceaccount.com is real; *@example.com, *@test.iam.gserviceaccount.com or fixture-shaped emails are doc samples, demote.",
509
+ "If the file lives under examples/, tests/, fixtures/, terraform-module-examples/, or a documented quickstart path AND no GOOGLE_APPLICATION_CREDENTIALS env points at it, demote."
510
+ ]
494
511
  },
495
512
  {
496
513
  "id": "kubeconfig-with-static-token",
@@ -499,7 +516,12 @@
499
516
  "description": "Static kube token persists in dotfile.",
500
517
  "confidence": "deterministic",
501
518
  "deterministic": true,
502
- "attack_ref": "T1552.001"
519
+ "attack_ref": "T1552.001",
520
+ "false_positive_checks_required": [
521
+ "If the cluster server URL is https://127.0.0.1:* / https://localhost:* / *.kind / minikube / k3d / docker-for-desktop — this is a local-only kubeconfig with no external blast radius; demote to lower confidence.",
522
+ "Verify the token field is not the documented kind/minikube/k3d default-bootstrap-token shape (length and prefix match the local-dev distro). If so, demote.",
523
+ "If the kubeconfig sits inside a CI runner workspace (path matches /home/runner/, /github/workspace/, /builds/, /workspace/) and the token is OIDC-exchanged at job start, treat as ephemeral; demote."
524
+ ]
503
525
  },
504
526
  {
505
527
  "id": "ai-api-egress-from-unexpected-process",
@@ -29,7 +29,9 @@
29
29
  "on_fail": "halt"
30
30
  }
31
31
  ],
32
- "mutex": [],
32
+ "mutex": [
33
+ "library-author"
34
+ ],
33
35
  "feeds_into": [
34
36
  {
35
37
  "playbook_id": "kernel",
@@ -38,13 +40,19 @@
38
40
  {
39
41
  "playbook_id": "secrets",
40
42
  "condition": "always"
43
+ },
44
+ {
45
+ "playbook_id": "sbom",
46
+ "condition": "container-image-layers.length > 0"
41
47
  }
42
48
  ]
43
49
  },
44
50
  "domain": {
45
51
  "name": "Container runtime posture + manifest review",
46
52
  "attack_class": "container-escape",
47
- "atlas_refs": [],
53
+ "atlas_refs": [
54
+ "AML.T0010"
55
+ ],
48
56
  "attack_refs": [
49
57
  "T1611",
50
58
  "T1610",
@@ -213,7 +221,7 @@
213
221
  ]
214
222
  },
215
223
  "direct": {
216
- "threat_context": "Container escape attack class in 2025-2026 is dominated by the runc / containerd / kubelet CVE chain. CVE-2024-21626 'Leaky Vessels' (runc <1.1.12 working-directory race fd leak into host) shipped Jan 2024 with public PoC and is the canonical container-escape primitive; subsequent runc/containerd CVEs follow the same pattern (host-resource leakage via misconfigured isolation). Mandiant 2025 IR report: ~22% of cloud-tenant compromises involved a container-escape step. The escape is exquisitely sensitive to manifest posture: privileged: true grants the attacker the full host kernel (LPE without escape); hostPID/hostNetwork/hostIPC grant cross-pod visibility; runAsUser: 0 + writable host mount = direct host write. seccompProfile + AppArmor profile presence is the primary mitigation. Manifests in repos are the attestation-vs-reality battleground — admission controllers reject some but not all anti-patterns, depending on policy maturity.",
224
+ "threat_context": "Container escape attack class in 2025-2026 is dominated by the runc / containerd / kubelet CVE chain. Public runc / containerd / kubelet escape primitives — including the 2024 'Leaky Vessels' working-directory race class establish the canonical pattern: host-resource leakage (fd, mount, /proc) via misconfigured isolation. Subsequent CVEs in the runc/containerd/kubelet chain follow the same shape. Mandiant 2025 IR report: ~22% of cloud-tenant compromises involved a container-escape step. The escape is exquisitely sensitive to manifest posture: privileged: true grants the attacker the full host kernel (LPE without escape); hostPID/hostNetwork/hostIPC grant cross-pod visibility; runAsUser: 0 + writable host mount = direct host write. seccompProfile + AppArmor profile presence is the primary mitigation. Manifests in repos are the attestation-vs-reality battleground — admission controllers reject some but not all anti-patterns, depending on policy maturity.",
217
225
  "rwep_threshold": {
218
226
  "escalate": 85,
219
227
  "monitor": 65,
@@ -417,7 +425,12 @@
417
425
  "description": "Container will run as root inside the namespace. Combined with any namespace escape, root-on-host.",
418
426
  "confidence": "deterministic",
419
427
  "deterministic": true,
420
- "attack_ref": "T1611"
428
+ "attack_ref": "T1611",
429
+ "false_positive_checks_required": [
430
+ "If the FROM base is a distroless / chainguard / nonroot variant (gcr.io/distroless/*:nonroot, cgr.dev/chainguard/*:latest, *:*-nonroot, scratch with a static binary) AND no later RUN/USER escalates to root, the runtime UID is nonroot by base; demote to miss.",
431
+ "If the Kubernetes pod spec consuming this image sets runAsNonRoot: true + a non-zero runAsUser, kubelet refuses to start the container as root; demote to lower confidence.",
432
+ "If the Dockerfile is under a multi-stage build and only the final stage's USER is missing while an intermediate builder stage runs as root (acceptable for builder stages), check the final stage only."
433
+ ]
421
434
  },
422
435
  {
423
436
  "id": "dockerfile-curl-pipe-bash",
@@ -426,7 +439,12 @@
426
439
  "description": "Build-time supply-chain compromise primitive. Compromised CDN or DNS rebind = arbitrary code in image.",
427
440
  "confidence": "deterministic",
428
441
  "deterministic": true,
429
- "attack_ref": "T1195.002"
442
+ "attack_ref": "T1195.002",
443
+ "false_positive_checks_required": [
444
+ "If the curl target is a major-vendor official install path (sh.rustup.rs, get.docker.com, get.pnpm.io, raw.githubusercontent.com/nvm-sh/nvm, sigstore/cosign release URL) AND the pipe is preceded by a documented sha256/gpg verify step in the same RUN, the chain is integrity-checked; demote to lower confidence.",
445
+ "If the URL is an internal-mirror with --tlsv1.3 + --proto =https + a pinned --cacert and the org's release-engineering runbook documents this mirror, treat as in-policy; demote.",
446
+ "Confirm the RUN does not chain to an `sudo` / privilege-elevation primitive — pipe-to-shell as an unprivileged builder USER materially reduces blast radius; report at high but not deterministic."
447
+ ]
430
448
  },
431
449
  {
432
450
  "id": "compose-privileged",
@@ -444,7 +462,12 @@
444
462
  "description": "Dangerous capability granted. SYS_ADMIN especially is functionally equivalent to root-on-host.",
445
463
  "confidence": "deterministic",
446
464
  "deterministic": true,
447
- "attack_ref": "T1611"
465
+ "attack_ref": "T1611",
466
+ "false_positive_checks_required": [
467
+ "If the container is a node-exporter / cadvisor / falco / sysdig / metrics-collector sidecar AND its image and pod identity match a documented host-introspection allowlist, the capability is intentional; demote to lower confidence (still report; revisit boundary).",
468
+ "If cap_drop: [ALL] precedes cap_add AND the user namespace is remapped (userns-remap configured at the daemon level), the effective root inside the container is unprivileged on the host; report at high but not deterministic.",
469
+ "If the compose file is under tests/, integration/, e2e/ or a development-only directory AND is excluded from production deploy pipelines (check CI for compose-file references), treat as non-shipped configuration."
470
+ ]
448
471
  },
449
472
  {
450
473
  "id": "compose-host-network",
@@ -453,7 +476,11 @@
453
476
  "description": "Host namespace sharing. Cross-process visibility + tampering primitive.",
454
477
  "confidence": "deterministic",
455
478
  "deterministic": true,
456
- "attack_ref": "T1610"
479
+ "attack_ref": "T1610",
480
+ "false_positive_checks_required": [
481
+ "If the service is a known service-mesh data-plane (envoy / linkerd-proxy / istio-proxy / cilium-agent) or a host-metrics sidecar (node-exporter / cadvisor) AND the deployment is documented on an operator-maintained host-network allowlist, demote.",
482
+ "Verify the compose file is not a dev-only docker-compose.override.yml that won't ship — diff against the production compose; if host-network is dev-only, mark in-scope-for-dev-only."
483
+ ]
457
484
  },
458
485
  {
459
486
  "id": "compose-docker-sock-mount",
@@ -43,7 +43,9 @@
43
43
  "domain": {
44
44
  "name": "Per-user credential store inventory + identity-assurance posture",
45
45
  "attack_class": "identity-abuse",
46
- "atlas_refs": [],
46
+ "atlas_refs": [
47
+ "AML.T0055"
48
+ ],
47
49
  "attack_refs": [
48
50
  "T1078",
49
51
  "T1552.001",
@@ -418,7 +420,12 @@
418
420
  "description": "Long-lived AWS IAM user key. AAL1-equivalent. Static credential.",
419
421
  "confidence": "deterministic",
420
422
  "deterministic": true,
421
- "attack_ref": "T1552.001"
423
+ "attack_ref": "T1552.001",
424
+ "false_positive_checks_required": [
425
+ "If the AKIA* value is AKIAIOSFODNN7EXAMPLE / a documented AWS-sample credential pair, demote — these are AWS-published doc fixtures.",
426
+ "Verify the key is live via `aws sts get-caller-identity --profile <name>` (or dry-run equivalent). If the key is already deactivated / deleted upstream, demote to lower confidence (still flag for cleanup).",
427
+ "If the profile name pattern matches an org-documented break-glass profile (e.g. profile = 'breakglass-*' with a documented quarterly-rotation procedure tied to it), accept the exception with a TTL test."
428
+ ]
422
429
  },
423
430
  {
424
431
  "id": "kube-static-token",
@@ -445,7 +452,12 @@
445
452
  "description": "Docker registry credentials in cleartext (base64 is not encryption). credHelpers/credsStore would route to OS keychain or cloud-IAM-federated path.",
446
453
  "confidence": "deterministic",
447
454
  "deterministic": true,
448
- "attack_ref": "T1552.001"
455
+ "attack_ref": "T1552.001",
456
+ "false_positive_checks_required": [
457
+ "Decode the auth value — if the decoded user is '<token>' / 'AWS' / 'oauth2accesstoken' / '00000000-0000-0000-0000-000000000000' (vendor-documented pseudo-users for short-lived token auth) AND the docker login was scripted with an exchange step, the credential is ephemeral; demote.",
458
+ "If the registry is a local-only registry (127.0.0.1:*, registry.local, kind.local, *.svc.cluster.local) on a dev workstation, blast radius is local; report at high but not deterministic.",
459
+ "Verify the credsStore field is not set globally (top-level credsStore overrides per-registry omission); if globally configured, demote."
460
+ ]
449
461
  },
450
462
  {
451
463
  "id": "npm-pat-present",
@@ -496,7 +508,12 @@
496
508
  "description": "Permissive permissions on a credential file. Local-user theft primitive.",
497
509
  "confidence": "deterministic",
498
510
  "deterministic": true,
499
- "attack_ref": "T1552.004"
511
+ "attack_ref": "T1552.004",
512
+ "false_positive_checks_required": [
513
+ "If the host filesystem is on Windows / WSL with no POSIX mode enforcement OR is a network share where mode bits are emulated, posix-mode is meaningless — verify the share is ACL-protected (e.g. ntfs ACL grants only the user); demote when ACL-tight.",
514
+ "If the file is a 0-byte placeholder / symlink to a credential broker socket or to a tmpfs path that's wiped on logout, the readable bits do not yield a usable credential; demote.",
515
+ "On a shared multi-user host the operator may have an explicit ACL-by-design model (e.g. 0640 with a group ACL granting the deploy-group read). If the runbook documents the intent AND `getfacl` confirms the named-group restriction, accept the exception."
516
+ ]
500
517
  },
501
518
  {
502
519
  "id": "all-stores-empty-or-federated",
@@ -393,77 +393,77 @@
393
393
  },
394
394
  {
395
395
  "id": "hash-primitive-call-sites",
396
- "type": "file_path",
396
+ "type": "file",
397
397
  "source": "Grep across the repo (excluding test/spec/fixture/node_modules/vendor/.venv/target/dist/build) for hash-primitive call sites. Patterns: `crypto.createHash\\(`, `crypto.createHmac\\(`, `hashlib\\.(md5|sha1|sha224|sha256|sha384|sha512|blake2b|blake2s|sha3_)`, `MessageDigest\\.getInstance\\(`, `Digest::(MD5|SHA1|SHA256)`, `hash/md5`, `hash/sha1`, `\"md5\"`, `\"sha1\"`, `\"sha-1\"`, `\"sha256\"`, `\"sha3-256\"`. Use Grep with multiline=true where the algorithm-name string is on a different line from the constructor.",
398
398
  "description": "Every hash-primitive call site. Distinguish security-context usage (signature input, MAC input, integrity check, password derivation, token derivation) from non-security usage (cache key, ETag, dedup). The non-security distinction must be evidenced inline; absent evidence, treat as security-context.",
399
399
  "required": true
400
400
  },
401
401
  {
402
402
  "id": "cipher-and-kex-call-sites",
403
- "type": "file_path",
403
+ "type": "file",
404
404
  "source": "Grep for cipher and KEX call sites: `createCipheriv\\(`, `createDecipheriv\\(`, `crypto\\.publicEncrypt\\(`, `crypto\\.privateDecrypt\\(`, `createDiffieHellman\\(`, `createECDH\\(`, `crypto\\.generateKeyPair`, `Cipher\\.getInstance\\(`, `aesgcm`, `ChaCha20Poly1305`, `\\.(seal|open)\\(`, `OpenSSL::Cipher`, hardcoded curve names `\"P-256\"`, `\"secp256r1\"`, `\"prime256v1\"`, `\"P-384\"`, `\"secp384r1\"`, `\"P-521\"`, `\"secp521r1\"`, `\"secp256k1\"`, `\"X25519\"`, `\"X448\"`.",
405
405
  "description": "Cipher and key-exchange call sites. Identify mode (GCM/CBC/CTR/ECB), curve, key size, IV-generation pattern. ECB mode anywhere is a hard fail. CBC without HMAC is a hard fail. AES-128 without GCM authenticator is a finding.",
406
406
  "required": true
407
407
  },
408
408
  {
409
409
  "id": "signature-call-sites",
410
- "type": "file_path",
410
+ "type": "file",
411
411
  "source": "Grep for signature operations: `crypto\\.sign\\(`, `crypto\\.verify\\(`, `Signature\\.getInstance\\(`, `\\.sign_pss\\(`, `\\.verify_pss\\(`, `RSA-PSS`, `RSA-PKCS1`, `ECDSA`, `Ed25519`, `Ed448`, `ML-DSA`, `Dilithium`, `SLH-DSA`, `SPHINCS`. Capture key sizes for RSA (look for `modulusLength`, `key_size`, `--rsa-2048` literals), curve choice for ECDSA, hash choice paired with signature (RSA-SHA1 is a hard fail).",
412
412
  "description": "Signature scheme inventory. RSA-1024 anywhere is a hard fail; RSA-2048 with > 5-year sensitivity requires PQC roadmap; ECDSA-P256 acceptable today but needs hybrid ML-DSA migration plan; bare RSA-PKCS1 (not PSS) for new signatures is a finding.",
413
413
  "required": true
414
414
  },
415
415
  {
416
416
  "id": "kdf-call-sites",
417
- "type": "file_path",
417
+ "type": "file",
418
418
  "source": "Grep for key-derivation calls: `pbkdf2(Sync)?\\(`, `PBKDF2`, `hashlib\\.pbkdf2_hmac`, `bcrypt\\.(hash|hashSync|compare)`, `scrypt(Sync)?\\(`, `argon2\\.(hash|verify)`, `argon2id`, `hkdf\\(`, `HKDF`, `derive_key`. For each, extract the cost parameters: PBKDF2 iterations, bcrypt cost factor, scrypt N/r/p, argon2 t/m/p.",
419
419
  "description": "Key-derivation parameter inventory. Apply OWASP 2023 minimums: PBKDF2-HMAC-SHA256 >= 600,000; PBKDF2-HMAC-SHA512 >= 210,000; bcrypt cost >= 12; scrypt N >= 2^17, r=8, p=1; argon2id m >= 19 MiB (19456 KiB), t >= 2, p >= 1. Any parameter below minimum is a finding.",
420
420
  "required": true
421
421
  },
422
422
  {
423
423
  "id": "rng-call-sites",
424
- "type": "file_path",
424
+ "type": "file",
425
425
  "source": "Grep for RNG sources: `Math\\.random\\(`, `random\\.random\\(`, `random\\.randint\\(`, `random\\.choice\\(`, `rand\\(`, `srand\\(`, `mt_rand\\(`, `secrets\\.(token_|randbits|choice)`, `crypto\\.randomBytes\\(`, `crypto\\.getRandomValues\\(`, `crypto\\.randomUUID\\(`, `os\\.urandom\\(`, `getrandom\\(`, `SecureRandom`, `OsRng`, `ThreadRng`, `/dev/urandom`, `/dev/random`. Capture file_path:line for each.",
426
426
  "description": "RNG-source inventory. Production-context Math.random / random.random / rand without cryptographic-RNG fallback is CWE-338. Distinguish test/spec/fixture usage explicitly via path allowlist; production usage requires a cryptographic RNG.",
427
427
  "required": true
428
428
  },
429
429
  {
430
430
  "id": "hardcoded-key-material",
431
- "type": "file_path",
431
+ "type": "file",
432
432
  "source": "Grep for hardcoded crypto material: PEM markers `-----BEGIN (RSA |EC |DSA |PRIVATE |PUBLIC |CERTIFICATE )?(PRIVATE|PUBLIC) KEY-----`, SSH key prefixes `ssh-rsa AAAA`, `ssh-ed25519 AAAA`, `ecdsa-sha2-nistp256 AAAA`, hex-blob heuristics for keys (>= 64 hex chars on a single literal line), base64-encoded blobs >= 256 chars in source files. Cross-reference with the `secrets` playbook for the exfil-secret angle; here the focus is library-author shipping defaults that look like keys (e.g. example certs, demo keys, sample HMAC seeds that downstream consumers fail to rotate).",
433
433
  "description": "Hardcoded key material shipped with the library. Library-author angle: any 'demo' or 'example' key that downstream consumers fail to rotate becomes a universal-default vulnerability (cf. embedded-router demo keys, Wi-Fi default WPA keys, IoT bootloader signing keys).",
434
434
  "required": false
435
435
  },
436
436
  {
437
437
  "id": "tls-config-construction",
438
- "type": "file_path",
438
+ "type": "file",
439
439
  "source": "Grep for in-code TLS context construction: `tls\\.createSecureContext`, `tls\\.createServer`, `https\\.createServer`, `ssl\\.SSLContext\\(`, `ssl\\.create_default_context`, `rustls::ServerConfig`, `rustls::ClientConfig`, `tls\\.Config\\{`, `SSL_CTX_new`, options like `minVersion`, `maxVersion`, `secureProtocol`, `ciphers`, `ecdhCurve`, `sigalgs`, `groups`, `ALPNProtocols`.",
440
440
  "description": "In-code TLS configuration. Library authors that construct TLS contexts internally must default to TLS 1.3 minimum, X25519MLKEM768 group preference (when openssl >= 3.5 detected), modern cipher list. Hardcoded `secureProtocol: 'TLSv1_method'` or `minVersion: 'TLSv1'` is a hard fail.",
441
441
  "required": false
442
442
  },
443
443
  {
444
444
  "id": "pqc-adoption-signals",
445
- "type": "file_path",
445
+ "type": "file",
446
446
  "source": "Grep for PQC adoption: `ml[-_]?kem`, `ml[-_]?dsa`, `slh[-_]?dsa`, `kyber`, `dilithium`, `sphincs`, `falcon`, `kemEncapsulate`, `kemDecapsulate`, `EVP_KEM_`, `OQS_KEM_`, `oqsprovider`, `liboqs`, `noble-post-quantum`, `pqcrypto::`, `aws-lc-rs::pqc`, `circl/sign/dilithium`, `circl/kem/kyber`.",
447
447
  "description": "PQC adoption signals. If `pqc-readiness-gap` directive runs, this artifact is the primary input. Distinguish concrete cryptographic operations from configuration strings, feature-flag names, and comments.",
448
448
  "required": false
449
449
  },
450
450
  {
451
451
  "id": "fips-provider-activation",
452
- "type": "file_path",
452
+ "type": "file",
453
453
  "source": "Grep for FIPS-mode activation: `OSSL_PROVIDER_load.*fips`, `crypto\\.setFips\\(`, `openssl::provider::Provider::load_default`, `Provider::load.*\"fips\"`, openssl.cnf or fipsmodule.cnf files in the repo, environment-variable references to `OPENSSL_FIPS`, `OPENSSL_CONF`. Capture whether the activation is conditional (e.g. only if env var set) or unconditional.",
454
454
  "description": "FIPS-provider activation evidence. The `fips-validation-status` directive uses this to distinguish runtime FIPS activation from link-time FIPS claims.",
455
455
  "required": false
456
456
  },
457
457
  {
458
458
  "id": "vendored-crypto-tree",
459
- "type": "file_path",
459
+ "type": "file",
460
460
  "source": "Glob for vendored crypto: `vendor/**/{crypto,openssl,sodium,nacl,kyber,dilithium,sphincs,curve25519,blake2,sha3,argon2}*`, `third_party/**/*crypto*`, `crates/**/*crypto*` (excluding the package's own crypto module). Look for upstream-reference files: `UPSTREAM`, `ORIGIN`, `PROVENANCE.md`, `.upstream-commit`, integrity hashes in lockfiles.",
461
461
  "description": "Vendored cryptographic primitives. Library authors sometimes vendor crypto to reduce dep tree or for licensing reasons. Without provenance + integrity audit, vendored crypto is a supply-chain backdoor opportunity.",
462
462
  "required": false
463
463
  },
464
464
  {
465
465
  "id": "ci-crypto-tests",
466
- "type": "file_path",
466
+ "type": "file",
467
467
  "source": "Glob for CI configs: `.github/workflows/**/*.yml`, `.gitlab-ci.yml`, `.circleci/config.yml`, `azure-pipelines.yml`, `Jenkinsfile`. Grep for crypto-test invocations, FIPS-test runs, constant-time analysis tools (`dudect`, `valgrind --tool=memcheck` on secret-dependent code, `ctgrind`).",
468
468
  "description": "Build-time crypto verification. Absence of constant-time tests on vendored PQC primitives is a finding for the `pqc-readiness-gap` directive.",
469
469
  "required": false
@@ -559,7 +559,12 @@
559
559
  "value": "Any file imports or constructs an MD5 / SHA1 hash and the output flows into a security context. Patterns: `crypto\\.createHash\\(['\"](md5|sha1|sha-1)['\"]\\)`, `hashlib\\.(md5|sha1)\\(`, `MessageDigest\\.getInstance\\(['\"](MD5|SHA-1)['\"]\\)`, `crypto/md5`, `crypto/sha1`, `Digest::(MD5|SHA1)\\.`",
560
560
  "description": "Weak hash primitive shipped in library source. Hard fail unless inline comment justifies non-security usage AND no flow into auth/integrity code path.",
561
561
  "confidence": "deterministic",
562
- "deterministic": true
562
+ "deterministic": true,
563
+ "false_positive_checks_required": [
564
+ "If the call site is under tests/, spec/, fixtures/, examples/ or carries an inline `// non-security: <reason>` / `# non-cryptographic: <reason>` comment AND the hash output flows into a checksum-only path (ETag, content-addressed cache key, dedupe), demote to miss.",
565
+ "If the file implements a documented legacy-protocol shim (TLS interop, ntlm, sha1-rsa cert parsing for compat) and the hash is consumed by a verify-only path against externally-fixed inputs, accept with an expiry test (deprecation date).",
566
+ "Confirm the hash output reaches an authn/integrity sink via simple grep on the assigned variable name reaching crypto.verify / hmac / signature.update / token comparison. If no such flow exists in this file, demote."
567
+ ]
563
568
  },
564
569
  {
565
570
  "id": "weak-cipher-mode",
@@ -567,7 +572,12 @@
567
572
  "value": "AES with ECB mode anywhere: `aes-\\d+-ecb`, `AES/ECB/`, `Cipher\\.getInstance\\(['\"]AES['\"]\\)` (default mode ECB). Or DES/3DES anywhere: `des-cbc`, `des-ede3`, `\\\"des\\\"`, `\\\"3des\\\"`, `DES/`, `DESede/`. Or RC4: `\\\"rc4\\\"`, `arc4`, `ARCFOUR`.",
568
573
  "description": "Catastrophic cipher choice. ECB leaks plaintext patterns; DES/3DES is below current security margins; RC4 is broken.",
569
574
  "confidence": "deterministic",
570
- "deterministic": true
575
+ "deterministic": true,
576
+ "false_positive_checks_required": [
577
+ "If the path is under tests/ / fixtures/ / known-answer-tests/ and carries a `// test-only` or `# KAT vector` marker, this is an interop / known-answer test against a published vector; demote to miss.",
578
+ "If the library is explicitly a legacy-protocol parser (e.g. an NTLM / Kerberos-RC4 / PKCS#12-3DES compatibility shim) AND its SECURITY.md declares the legacy scope, accept with a deprecation-deadline test rather than hard fail.",
579
+ "Confirm the construction is actually instantiated in a production code path — `grep -r '<cipher-var>' src/ --include='*.{js,ts,py,java,go}'`. If only referenced in `if (legacy) {}` dead-branch code, demote."
580
+ ]
571
581
  },
572
582
  {
573
583
  "id": "rsa-1024-anywhere",
@@ -649,7 +659,12 @@
649
659
  "value": "`secureProtocol:\\s*['\"](TLSv1_method|TLSv1_1_method|SSLv23_method|SSLv3_method)['\"]`, `minVersion:\\s*['\"](TLSv1(\\.0|\\.1)?)['\"]`, `ssl_version=ssl\\.PROTOCOL_TLSv1(_1)?`, `MinTlsVersion::TLSv1`.",
650
660
  "description": "TLS < 1.2 minimum in shipped TLS-context construction.",
651
661
  "confidence": "deterministic",
652
- "deterministic": true
662
+ "deterministic": true,
663
+ "false_positive_checks_required": [
664
+ "If the path is under tests/ / fixtures/ AND the test purpose is asserting that the library REJECTS the legacy protocol (negative test), demote.",
665
+ "If the construction is gated behind a feature flag whose default value is OFF AND the README documents the flag as an opt-in for legacy compatibility only, treat as a deprecated-but-supported path rather than a default-insecure ship.",
666
+ "Confirm there is no override-construction later (e.g. a subsequent `setMinProtoVersion(TLS_1_3)` on the same context) — partial defaults are common; the effective minimum is the highest set."
667
+ ]
653
668
  },
654
669
  {
655
670
  "id": "no-crypto-agility-abstraction",
@@ -339,7 +339,7 @@
339
339
  },
340
340
  {
341
341
  "id": "libssl-libraries",
342
- "type": "file_path",
342
+ "type": "file",
343
343
  "source": "ldconfig -p | grep -E 'libssl|libcrypto|libtls' AND find /usr/lib /usr/local/lib -name 'libssl*' -o -name 'libcrypto*' 2>/dev/null",
344
344
  "description": "Installed TLS libraries — catches non-default OpenSSL builds, vendored libcrypto, LibreSSL, BoringSSL.",
345
345
  "required": false
@@ -453,7 +453,12 @@
453
453
  "value": "Within the openssl-kem-algorithms artifact (its `openssl list -signature-algorithms` half): output does NOT contain ML-DSA-44/65/87 AND does NOT contain SLH-DSA-*",
454
454
  "description": "TLS library cannot use PQC signatures. Certificate-chain PQC migration is blocked.",
455
455
  "confidence": "deterministic",
456
- "deterministic": true
456
+ "deterministic": true,
457
+ "false_positive_checks_required": [
458
+ "Confirm whether oqsprovider / aws-lc / wolfssl is loaded alongside OpenSSL — `openssl list -providers` may show a PQC-providing module that supplies ML-DSA via a non-default path. If so, demote.",
459
+ "Verify the binary is statically linked or chroot-jailed against a different libcrypto than the one being interrogated; rerun the list command using the actual library the service has loaded (lsof / /proc/<pid>/maps).",
460
+ "If the host's role is documented as classical-only (e.g. an air-gapped HSM-fronted signer with offline key custody) AND a separate PQC-signing tier exists upstream, accept with an explicit roadmap milestone."
461
+ ]
457
462
  },
458
463
  {
459
464
  "id": "openssl-pre-3-5",
@@ -461,7 +466,12 @@
461
466
  "value": "Within the openssl-version artifact: output starts with 'OpenSSL 1.', 'OpenSSL 2.', 'OpenSSL 3.0', 'OpenSSL 3.1', 'OpenSSL 3.2', 'OpenSSL 3.3', or 'OpenSSL 3.4'; cross-check libssl-libraries artifact to detect coexisting older libcrypto.so loaded via LD_LIBRARY_PATH or vendored builds (LibreSSL, BoringSSL, vendored OpenSSL under /usr/local/lib)",
462
467
  "description": "Pre-3.5 OpenSSL lacks native ML-KEM. Requires oqsprovider or upgrade.",
463
468
  "confidence": "deterministic",
464
- "deterministic": true
469
+ "deterministic": true,
470
+ "false_positive_checks_required": [
471
+ "If the host is on a vendor-supported LTS (RHEL 8/9, Ubuntu 20.04/22.04, SLES 15, Amazon Linux 2/2023), verify the distro's documented PQC backport status via `rpm -q --changelog openssl` / `dpkg -s openssl` — RHEL 9.5+, Ubuntu 24.04 ship oqsprovider as a package; mark backport state explicitly.",
472
+ "If openssl-providers also lists an active oqsprovider AND oqsprovider's ML-KEM appears in the kem-algorithms list, the pre-3.5 base is provider-augmented; demote to lower confidence (still flag the upgrade path).",
473
+ "Confirm the queried `openssl` binary is the one services link against (lsof on representative daemons + /proc/<pid>/maps grep for libcrypto). If services link against a newer vendored 3.5+ libcrypto, the system openssl version is misleading."
474
+ ]
465
475
  },
466
476
  {
467
477
  "id": "sshd-no-pqc-kex",
@@ -477,7 +477,11 @@
477
477
  "value": "Any exception register entry with rwep_at_acceptance >= 70 lacking (a) explicit calendar expiry, (b) named risk-acceptance owner at correct authority level, (c) tested compensating controls",
478
478
  "description": "Theater fingerprint #3 detection.",
479
479
  "confidence": "deterministic",
480
- "deterministic": true
480
+ "deterministic": true,
481
+ "false_positive_checks_required": [
482
+ "Confirm the artifact actually represents the live exception register. If the input is a draft / historical / archived register snapshot (filename includes -draft / -archive / -YYYY-Q< number >), demote.",
483
+ "If expiry/owner/controls are stored in a sidecar system (ServiceNow, Jira, IRM tool) linked by ID, the indicator may falsely fire on a register that intentionally normalises to ID-references. Verify the linked record's fields before flagging."
484
+ ]
481
485
  },
482
486
  {
483
487
  "id": "jurisdiction-without-framework",
@@ -485,7 +489,11 @@
485
489
  "value": "jurisdictional_footprint contains EU / UK / AU / SG / JP / IN / CA / HK / TW / IL / CH / ID / VN AND framework_mapping_matrix does NOT contain the corresponding binding framework (NIS2 / DORA / EU AI Act / CAF / Essential 8 / APRA / MAS TRM / NISC / CERT-In / OSFI B-10)",
486
490
  "description": "Theater fingerprint #4 detection — operating in a regulated jurisdiction without framework mapping.",
487
491
  "confidence": "deterministic",
488
- "deterministic": true
492
+ "deterministic": true,
493
+ "false_positive_checks_required": [
494
+ "If the organisation has filed a documented `out-of-scope` declaration with the relevant regulator (e.g. NIS2 size-threshold exclusion <50 employees + <EUR 10M turnover; DORA scoping out as non-financial entity; EU AI Act non-AI-deployer attestation) AND the declaration is current within the regulator's revalidation window, demote.",
495
+ "If the jurisdictional footprint is data-only (e.g. an EU IP block accessing a CDN, no establishment / no targeted offering) AND no EU data subjects' personal data is processed, the binding framework may not attach; confirm against the regulator's territoriality test."
496
+ ]
489
497
  },
490
498
  {
491
499
  "id": "mapping-without-tempo",
@@ -509,7 +517,11 @@
509
517
  "value": "Three or more theater fingerprints fire on the same framework control (e.g. ISO 27001:2022 A.8.30 fires patterns #1 + #2 + #6 simultaneously)",
510
518
  "description": "Compound theater — single control structurally insufficient across multiple threat classes.",
511
519
  "confidence": "deterministic",
512
- "deterministic": true
520
+ "deterministic": true,
521
+ "false_positive_checks_required": [
522
+ "Confirm the multiple fingerprints fire on the SAME control (not different controls aggregated against the same audit scope). Cross-fingerprint stacks against different controls are not compound theater; they are inventory of distinct gaps.",
523
+ "Verify each constituent fingerprint individually passed its own FP checks. If any of the three is itself a coincidence-hit (e.g. exception-missing-expiry on a draft register), recompute the count without it."
524
+ ]
513
525
  }
514
526
  ],
515
527
  "false_positive_profile": [
@@ -35,7 +35,9 @@
35
35
  "on_fail": "warn"
36
36
  }
37
37
  ],
38
- "mutex": [],
38
+ "mutex": [
39
+ "kernel"
40
+ ],
39
41
  "feeds_into": [
40
42
  {
41
43
  "playbook_id": "kernel",
@@ -401,7 +403,11 @@
401
403
  "description": "/proc/kallsyms is world-readable; KASLR is effectively defeated for any local user. Decisive for kernel LPE exploitability.",
402
404
  "confidence": "deterministic",
403
405
  "deterministic": true,
404
- "attack_ref": "T1068"
406
+ "attack_ref": "T1068",
407
+ "false_positive_checks_required": [
408
+ "If the host is in an active kdump / perf / kernel-debugging session AND the rationale is captured in the operator runbook with a documented restoration deadline, accept with a TTL test (must flip to >=1 within N days).",
409
+ "Confirm /proc/kallsyms actually leaks pointers — `head -1 /proc/kallsyms` as an unprivileged user. If addresses are zeroed despite kptr_restrict=0 (e.g. CAP_SYSLOG-only path active via systemd), demote to lower confidence."
410
+ ]
405
411
  },
406
412
  {
407
413
  "id": "unprivileged-userns-enabled",
@@ -428,7 +434,12 @@
428
434
  "description": "Yama ptrace_scope=0 allows any process to ptrace any same-UID process. Credential-theft + privilege-pivot primitive.",
429
435
  "confidence": "deterministic",
430
436
  "deterministic": true,
431
- "attack_ref": "T1212"
437
+ "attack_ref": "T1212",
438
+ "false_positive_checks_required": [
439
+ "If the host is a developer workstation in a documented debug-allowlist AND an enforcing MAC profile (AppArmor `aa-status` enforced / SELinux `getenforce` == Enforcing) restricts cross-UID ptrace, the kernel-level open is constrained at a higher layer; demote to lower confidence.",
440
+ "If a containerised workload depends on ptrace for documented observability tooling (strace-based tracer, gdb-based debugger run-as-CAP_SYS_PTRACE), confirm the broader scope is justified by that workload and is not host-wide.",
441
+ "Confirm the system isn't a single-user dev VM with no network exposure — ptrace_scope=0 on an isolated VM has materially lower blast radius than on a multi-tenant host."
442
+ ]
432
443
  },
433
444
  {
434
445
  "id": "kaslr-disabled-at-boot",
@@ -437,7 +448,11 @@
437
448
  "description": "Boot-time KASLR disabled. Makes catalogued kernel LPEs deterministic.",
438
449
  "confidence": "deterministic",
439
450
  "deterministic": true,
440
- "attack_ref": "T1068"
451
+ "attack_ref": "T1068",
452
+ "false_positive_checks_required": [
453
+ "If the host is in an active kdump / kgdb / kernel-debugging session AND the rationale is documented in the operator runbook with a documented restoration deadline, accept with TTL.",
454
+ "Confirm the cmdline option actually took effect — `dmesg | grep -i kaslr` should show KASLR offsets when active. An nokaslr token in cmdline but a KASLR-active kernel (some distros override) means the boot parameter was ignored; demote."
455
+ ]
441
456
  },
442
457
  {
443
458
  "id": "mitigations-off",
@@ -446,7 +461,11 @@
446
461
  "description": "Boot-time CPU mitigations disabled. Spectre/Meltdown/MDS/Retbleed/Downfall class becomes exploitable.",
447
462
  "confidence": "deterministic",
448
463
  "deterministic": true,
449
- "attack_ref": "T1068"
464
+ "attack_ref": "T1068",
465
+ "false_positive_checks_required": [
466
+ "If the host is HPC/benchmark-tagged (slurm node, MPI scratch node, vendor-perf-test rig) AND not network-exposed AND mitigations=off is documented in the operator runbook with a network-isolation control, accept the exception with a quarterly revalidation test.",
467
+ "Confirm the host is single-tenant (no multi-user, no untrusted workloads). Mitigations are speculative-execution defences against same-host attackers; on a single-tenant control-plane the threat may not apply."
468
+ ]
450
469
  },
451
470
  {
452
471
  "id": "selinux-not-enforcing",
@@ -45,7 +45,9 @@
45
45
  "on_fail": "warn"
46
46
  }
47
47
  ],
48
- "mutex": [],
48
+ "mutex": [
49
+ "hardening"
50
+ ],
49
51
  "feeds_into": [
50
52
  {
51
53
  "playbook_id": "sbom",
@@ -382,7 +384,11 @@
382
384
  "description": "Unprivileged user namespaces enabled — required for several catalogued LPE classes.",
383
385
  "confidence": "deterministic",
384
386
  "deterministic": true,
385
- "attack_ref": "T1611"
387
+ "attack_ref": "T1611",
388
+ "false_positive_checks_required": [
389
+ "If a documented rootless-container runtime (podman/rootless, buildah, lima, colima, GitHub Actions runners) is the workload AND unprivileged userns is a documented requirement, accept the exception — but pair with an LSM (SELinux/AppArmor) enforcing profile that constrains exec/mount inside the userns.",
390
+ "Verify CONFIG_USER_NS is built into the kernel — distros that ship with userns disabled at config-time make the sysctl moot regardless of value. `grep CONFIG_USER_NS /boot/config-$(uname -r)` should show =y for the indicator to be live."
391
+ ]
386
392
  },
387
393
  {
388
394
  "id": "unpriv-bpf-allowed",
@@ -391,7 +397,11 @@
391
397
  "description": "Unprivileged BPF allowed — primitive for several kernel LPE classes.",
392
398
  "confidence": "deterministic",
393
399
  "deterministic": true,
394
- "attack_ref": "T1068"
400
+ "attack_ref": "T1068",
401
+ "false_positive_checks_required": [
402
+ "Verify CONFIG_BPF_SYSCALL=y AND CONFIG_BPF_JIT=y in the running kernel config (`grep CONFIG_BPF /boot/config-$(uname -r)`). If BPF is compiled out, the sysctl is moot; demote.",
403
+ "If an enforcing LSM profile (SELinux / AppArmor) restricts bpf() syscall for unprivileged users via a tested policy, the kernel-level open is constrained at a higher layer; demote to lower confidence."
404
+ ]
395
405
  }
396
406
  ],
397
407
  "false_positive_profile": [