Verifying Binary Patches with Stella Ops Micro-Witnesses
Audience: security engineers, auditors, and procurement reviewers who need to confirm that a shipped binary actually carries a specific security patch — not just that the patch exists upstream.
This guide explains how to generate, verify, and bundle binary micro-witnesses with the stella CLI to prove patch status at the binary level.
Overview
Binary micro-witnesses provide cryptographic proof of patch status at the binary level. Unlike source-level attestations, they verify what is actually deployed, not what should be deployed.
Use Cases
- Procurement: Verify vendor claims that CVEs are fixed in delivered binaries
- Audit: Provide evidence of patch status for compliance
- Incident Response: Quickly determine exposure across binary inventory
- Supply Chain: Validate that build outputs match expected patch state
Quick Start
Generate a Witness
stella witness generate /path/to/libssl.so.3 \
--cve CVE-2024-0567 \
--sbom sbom.cdx.json \
--output witness.json
stella witness generate requires the patch-verification service to be wired into the CLI host. If the service is not available, or if the verification itself fails, the command exits with code 9 (NotImplemented) and does not emit a placeholder witness.
NOT IMPLEMENTED —
--sign/--rekor. As of the current code, passing either--signor--rekortostella witness generatecauses the command to exit early with code9and the message: “witness signing and Rekor publication require the Attestor/Signer integration. No local placeholder signature or transparency metadata was generated.” Local detached-signature and Rekor inclusion-metadata generation exist in the handler but are gated off pending the Attestor/Signer integration. Until that integration lands, generate unsigned witnesses and rely on the binary/SBOM digests plus thedeltaSigDigestback-reference for integrity. See Transparency Logging.
Verify a Witness
# Default verification (signature + any embedded Rekor metadata + SBOM digest when --sbom is supplied)
stella witness verify witness.json
# Offline verification (air-gapped). NB: verify is always offline today, so --offline
# is currently a no-op flag — see the CLI Reference note for stella witness verify.
stella witness verify witness.json --offline
Verification checks the witness’s detached-signature metadata and, when a rekor block is present, re-derives and checks the inclusion metadata; it also compares the SBOM digest when --sbom is supplied. Note that current generate output is unsigned and carries no rekor block (see Transparency Logging), so an out-of-the-box witness reports the signature as not verified.
Create Portable Bundle
stella witness bundle witness.json --output ./audit-bundle
Understanding Verdicts
| Verdict | Meaning |
|---|---|
patched | Binary matches patched version signature |
vulnerable | Binary matches vulnerable version signature |
inconclusive | Unable to determine (insufficient evidence) |
partial | Some functions patched, others not |
Confidence Scores
Confidence ranges from 0.0 to 1.0 (the predicate schema enforces this range). The bands below are interpretive guidance for readers, not thresholds enforced by the witness schema:
- 0.95+: High confidence - multiple functions matched with strong evidence
- 0.80-0.95: Medium confidence - some functions matched
- <0.80: Low confidence - limited evidence or compiler variation
The underlying patch-verification engine reports a
Verified(→patched) result when match confidence meetsMinConfidenceThreshold, which defaults to 0.70 inPatchVerificationOptions. A witness can therefore carry apatchedverdict with a confidence between 0.70 and 0.80 — below the “Medium” band above. Treat the bands as a presentation aid and the 0.70 default as the engine’s actual decision point.
Evidence Types
Each evidence entry carries a function, a state, a score (0.0-1.0), the method used, and an optional hash. The evidence array must contain at least one entry and is capped at 10 (top matches only) per the predicate schema.
{
"evidence": [
{
"function": "SSL_CTX_new",
"state": "patched",
"score": 0.97,
"method": "semantic_ksg",
"hash": "..."
}
]
}
The state field accepts one of: patched, vulnerable, modified, unchanged, unknown.
Match Methods
The predicate schema constrains evidence[].method to the following enum:
| Method | Description | Robustness |
|---|---|---|
byte_exact | Exact byte-level match | Fragile to recompilation |
cfg_structural | Control flow graph structure | Moderate |
semantic_ksg | Semantic key-semantics graph | Robust to optimization |
ir_semantic | IR-level semantic comparison | Most robust |
chunk_rolling | Rolling-chunk content hash | Moderate |
Source/schema mismatch (flagged). The values above are the schema-permitted set (
stellaops-binary-micro-witness.v1.schema.json). However, the CLIgeneratehandler currently derivesmethoddirectly from the patch-verification engine’sFingerprintMethodenum via.ToString().ToLowerInvariant(), which yieldstlsh,cfghash,instructionhash,symbolhash, orsectionhash. None of those are in the schema enum, so a witness produced by the currentgeneratepath will not validate against the published schema’smethodconstraint. This is an open inconsistency betweenWitnessCoreCommandHandlersand the predicate schema, not a documentation choice; treat the schema enum as the contract and the emitted strings as a known gap.
Offline Verification
For air-gapped environments:
Create bundle (witness predicate + verification scripts; no Rekor tile proof is embedded today — see the flag below):
stella witness bundle witness.json --output ./bundleTransfer bundle to air-gapped system
Verify offline:
# PowerShell .\verify.ps1 # Bash ./verify.sh
The bundle written by stella witness bundle contains:
witness.json— the witness predicate (copied verbatim from the input file)verify.ps1— PowerShell verification script (Windows)verify.sh— Bash verification script (Linux/macOS; usesjqto display fields)README.md— generated bundle summary (CVE, binary digest, verdict, confidence, computed-at)
The generated verify.ps1/verify.sh scripts parse and display the witness fields, then delegate to stella witness verify if the stella CLI is on PATH; if it is not, they print a warning and skip the signature/Rekor metadata checks.
Flags vs. behaviour (flagged).
stella witness bundleaccepts--include-binaryand--include-sbom, but the current handler does not copy the analyzed binary or the SBOM into the bundle — onlywitness.json, the two scripts, andREADME.mdare written regardless of those flags. Likewise, no Rekor tile proof is embedded today (see Transparency Logging — Rekor metadata generation is gated off). Plan bundle contents around the four files listed above.
Integration with SBOMs
Micro-witnesses can reference SBOM components:
{
"sbomRef": {
"sbomDigest": "sha256:...",
"purl": "pkg:deb/debian/openssl@3.0.11",
"bomRef": "openssl-3.0.11"
}
}
This links binary verification to your software inventory. All three sbomRef fields (sbomDigest, purl, bomRef) are optional in the schema. Note that the CLI generate path only populates sbomDigest (the SHA-256 of the --sbom file); purl and bomRef are reserved for callers that build the predicate programmatically.
Predicate Schema
predicateType(DSSE statement):https://stellaops.dev/predicates/binary-micro-witness@v1- JSON Schema
$id:https://stellaops.dev/schemas/predicates/binary-micro-witness.v1.schema.json(canonical file:src/Attestor/StellaOps.Attestor.Types/schemas/stellaops-binary-micro-witness.v1.schema.json)
The required top-level fields are schemaVersion, binary, cve, verdict, confidence, evidence, tooling, and computedAt. deltaSigDigest and sbomRef are optional. schemaVersion is pinned to the constant 1.0.0.
{
"schemaVersion": "1.0.0",
"binary": {
"digest": "sha256:...",
"purl": "pkg:...",
"arch": "linux-amd64",
"filename": "libssl.so.3"
},
"cve": {
"id": "CVE-2024-0567",
"advisory": "https://...",
"patchCommit": "abc123"
},
"verdict": "patched",
"confidence": 0.95,
"evidence": [...],
"deltaSigDigest": "sha256:...",
"sbomRef": {...},
"tooling": {
"binaryIndexVersion": "2.1.0",
"lifter": "b2r2",
"matchAlgorithm": "semantic_ksg"
},
"computedAt": "2026-01-28T12:00:00Z"
}
Schema notes grounded in stellaops-binary-micro-witness.v1.schema.json:
cve.idaccepts CVE, GHSA, or generic<PREFIX>-<number>identifiers — not just CVE.binary.digest,deltaSigDigest, andsbomRef.sbomDigestmust match^sha256:[a-fA-F0-9]{64}$.tooling.lifteris constrained tob2r2,ghidra, orradare2; the CLIgeneratepath always emitsb2r2.tooling.matchAlgorithmis constrained tosemantic_ksg,byte_exact,cfg_structural, orir_semantic. As withevidence[].method, the CLIgeneratepath instead emits the lowercasedFingerprintMethodname (e.g.tlsh), which is outside this enum — the same flagged mismatch noted under Match Methods.
Limitations
What Micro-Witnesses Prove
- A specific binary was analyzed
- Function signatures were compared against known patterns
- A verdict was computed with a confidence score
What They Do NOT Prove
- Binary authenticity (use SBOM attestations)
- Absence of other vulnerabilities (only specific CVE)
- Build provenance (use SLSA attestations)
Technical Limitations
- Heavy inlining may hide patched functions
- Stripped symbols reduce match accuracy
- Obfuscated binaries yield “inconclusive”
- Very old binaries may not have ground-truth signatures
Transparency Logging
NOT IMPLEMENTED (Draft/roadmap). Rekor transparency logging is not wired in the current CLI. Passing
--rekor(which also requires--sign) tostella witness generatecauses the command to exit with code9before any witness is produced, because both signing and Rekor publication are gated behind the Attestor/Signer integration. The handler contains deterministic local inclusion-metadata generation (entryId,logIndex,integratedTime,leafHash,rootHash) andstella witness verifycan re-derive and check that metadata if it is present in a witness, but thegeneratepath never reaches that code today.
The intended behaviour, once the Attestor/Signer integration lands, is:
- Witnesses are logged to the Rekor transparency log when
--rekoris specified - Provides tamper-evidence and lets auditors confirm a witness was not backdated
- Supports tile-based inclusion proofs
Until then, offline bundles do not embed Rekor tile proofs (see Offline Verification).
CLI Reference
stella witness generate
stella witness generate <binary> --cve <id> [options]
Arguments:
binary Path to binary file to analyze
Options:
-c, --cve <id> CVE identifier (required; validated at runtime)
-s, --sbom <path> Path to SBOM file (CycloneDX or SPDX) for component mapping
-o, --output <path> Output file (default: stdout)
--sign Sign the witness [NOT IMPLEMENTED — exits with code 9]
--rekor Log to Rekor transparency log [NOT IMPLEMENTED — exits with code 9; also requires --sign]
-f, --format Output format: json, envelope (default: json)
-v, --verbose Enable verbose output
Notes:
--cveparses without error if omitted, but the handler rejects an empty value at runtime (exit code1).- Requires a registered patch-verification service; if unavailable or if verification throws, the command exits
9(NotImplemented) and writes no witness.
stella witness verify
stella witness verify <witness> [options]
Arguments:
witness Path to witness file (JSON or DSSE envelope)
Options:
--offline Verify without network access [no-op — verify is always offline]
-s, --sbom <path> Validate SBOM digest against the witness sbomRef.sbomDigest
-f, --format Output format: text, json (default: text)
-v, --verbose Enable verbose output
--offlineis currently a no-op (flagged).stella witness verifyperforms no network access in either mode: signature checks use a local HMAC and any embeddedrekorblock is re-derived in-process. The--offlineflag only changes a verbose log line (Mode: offline (no network access)) inHandleVerifyAsync— it does not load a separate bundled proof or otherwise alter the verification path. Treat verify as always-offline; the flag is reserved for the future Rekor integration.
Exit codes: 0 when the witness passes (signature valid; Rekor proof valid when present; SBOM digest matches when --sbom is supplied), 5 (VerificationFailed) otherwise, and 1 if the witness file is missing or cannot be parsed. An unsigned witness reports the signature as “not verified” and fails the overall check.
stella witness bundle
stella witness bundle <witness> --output <dir> [options]
Arguments:
witness Path to witness file to bundle
Options:
-o, --output <dir> Output directory (required)
--include-binary Include analyzed binary [accepted but currently no-op]
--include-sbom Include SBOM file [accepted but currently no-op]
-v, --verbose Enable verbose output
Related Documentation
- BinaryIndex Architecture
- Attestor Module
- Delta-Sig Predicate Schema
- DeltaSig v2 Schema (module dossier)
