Catalog Format

All CBOM detection is driven by a declarative catalog so it can be maintained over time without code changes. The builtin catalog is embedded in the binary (internal/cbom/catalog/*.json). You can extend or replace it at runtime:

vulnetix cbom --catalog ./my-algos.json          # merge over the builtin (override by id)
vulnetix cbom --catalog ./only.json --no-builtin-catalog   # replace entirely

A catalog file is JSON with any of three top-level keys: algorithms, libraries, call_extractors.

Algorithm entry

{
  "id": "sha-256",                       // canonical SPDX id (override key)
  "name": "SHA-256",                     // canonical stored name
  "spdx_class": "Cryptographic-Hash-Function/Hash-Function",
  "oid": "2.16.840.1.101.3.4.2.1",
  "aliases": ["sha256", "sha_256", "sha2-256"],   // matched case/separator-insensitively
  "primitive": "hash",                   // CycloneDX algorithmProperties.primitive enum
  "crypto_functions": ["digest"],        // CycloneDX cryptoFunctions enum
  "classical_security_level": 128,
  "nist_quantum_security_level": 2,      // 0..6 (0 = not quantum-safe)
  "pqc_status": "quantum-safe",          // quantum-safe | quantum-vulnerable | deprecated | hybrid
  "standards": {"NIST": "approved", "BSI": "approved"},   // per-country matrix
  "source_patterns": {                   // language -> Go RE2 patterns (attribute this algorithm)
    "go": ["crypto/sha256"],
    "python": ["(?i)hashlib\\.sha256"]
  },
  "config_patterns": ["(?i)\\bSHA[_-]?256\\b"]   // matched in TLS/SSH/JWT/OpenSSL config
}

The primitive, crypto_functions, mode, padding and pqc_status values are validated against the CycloneDX enums at load time and by just gen-cbom.

Library entry

{
  "id": "liboqs",
  "name": "liboqs",
  "provider": "Open Quantum Safe",
  "languages": ["c", "cpp", "python", "go", "rust"],
  "purl_names": {"generic": "liboqs"},
  "import_patterns": ["#include\\s*<oqs/", "(?i)\\bOQS_(?:KEM|SIG)_"]
}

Call extractor

A call extractor captures an algorithm token from a generic crypto API; the token is normalized and resolved through the alias index, so arbitrary spellings map to one algorithm.

{"languages": ["javascript"], "pattern": "(?i)createHash\\(\\s*['\"]([\\w./-]+)['\"]", "role": "algorithm"}
// role: "algorithm" | "transform" (Java AES/CBC/PKCS5Padding) | "jwt" ("alg":"…")

Each extractor pattern must have exactly one capture group. All patterns are Go RE2 (no backreferences/lookaround).