Binary Diff Attestation
Overview
Binary Diff Attestation enables verification of binary-level changes between container images, producing cryptographically signed evidence of what changed at the ELF/PE section level. This capability is essential for:
- Vendor backport detection: Identify when a vendor has patched a binary without changing version numbers
- Supply chain verification: Prove that expected changes (and no unexpected changes) occurred between releases
- VEX evidence generation: Provide concrete evidence for “not_affected” or “fixed” vulnerability status claims
- Audit trail: Maintain verifiable records of binary modifications across deployments
Relationship to SBOM and VEX
Binary diff attestations complement SBOM and VEX documents:
| Artifact | Purpose | Granularity |
|---|---|---|
| SBOM | Inventory of components | Package/library level |
| VEX | Exploitability status | Vulnerability level |
| Binary Diff Attestation | Change evidence | Section/function level |
The attestation provides the evidence that supports VEX claims. For example, a VEX statement claiming a CVE is “fixed” due to a vendor backport can reference the binary diff attestation showing the .text section hash changed.
Architecture
Component Diagram
+-------------------+ +--------------------+ +--------------------+ +----------------------+
| OCI Registry |-->| Layer Extraction |-->| ELF Detection |-->| Section Hash Extract |
+-------------------+ +--------------------+ +--------------------+ +----------------------+
| base + target images
v
+-------------------+ +--------------------+ +------------------+ +------------------+
| Diff Computation |-->| Predicate Builder |-->| DSSE Signer |-->| Output Files |
+-------------------+ +--------------------+ +------------------+ +------------------+
Key Components
| Component | Location | Responsibility |
|---|---|---|
ElfSectionHashExtractor | Scanner.Analyzers.Native | Extract per-section SHA-256 hashes from ELF binaries |
BinaryDiffService | Cli.Commands.Scan | Orchestrate diff computation between two images |
BinaryDiffPredicateBuilder | Attestor.StandardPredicates | Construct BinaryDiffV1 predicate payloads |
BinaryDiffDsseSigner | Attestor.StandardPredicates | Sign predicates with DSSE envelopes |
AddBinaryDiffPredicates() registers the serializer, signer, and verifier as stateless singletons. The fluent IBinaryDiffPredicateBuilder is transient because it owns mutable subjects, findings, inputs, and metadata; sharing one instance would contaminate concurrent or sequential predicate constructions. The current CLI BinaryDiffService constructs a builder with its own options and TimeProvider, while scan diff --emit-dsse resolves the registered signer.
Data Flow
- Image Resolution: Resolve base and target image references to manifest digests
- Layer Extraction: Download and extract layers from both images
- Binary Identification: Identify ELF binaries in both filesystems
- Section Hash Computation: Compute SHA-256 for each target section in each binary
- Diff Computation: Compare section hashes between base and target
- Verdict Classification: Basic classification of unchanged vs modified binaries
- Predicate Construction: Build BinaryDiffV1 predicate with findings
- DSSE Signing: Sign predicate; optional transparency log submission is handled by attestor tooling
ELF Section Hashing
Target Sections
The following ELF sections are analyzed for hash computation:
| Section | Purpose | Backport Relevance |
|---|---|---|
.text | Executable code | High - Patched functions modify this section |
.rodata | Read-only data (strings, constants) | Medium - String constants may change with patches |
.data | Initialized global/static variables | Low - Rarely changes for security patches |
.symtab | Symbol table (function names, addresses) | High - Function signature changes |
.dynsym | Dynamic symbols (exports) | High - Exported API changes |
Hash Algorithm
Primary: SHA-256
- Industry standard, widely supported
- Collision-resistant for security applications
Optional: BLAKE3-256
- Faster computation for large binaries
- Enabled via configuration
Hash Computation
For each ELF binary:
1. Parse ELF header
2. Locate section headers
3. For each target section:
a. Read section contents
b. Compute SHA-256(contents)
c. Store: {name, offset, size, sha256}
4. Sort sections by name (lexicographic)
5. Return ElfSectionHashSet
Determinism Guarantees
All operations produce deterministic output:
| Aspect | Guarantee |
|---|---|
| Section ordering | Sorted lexicographically by name |
| Hash format | Lowercase hexadecimal, no prefix |
| Timestamps | From injected TimeProvider |
| JSON serialization | RFC 8785 canonical JSON |
The CLI produces local payload and DSSE files only. It does not submit to Rekor or attach the attestation automatically, and the current executable analysis path is ELF/section-hash based. PE/Mach-O and automatic CVE-specific patch verdicts remain outside this verified boundary.
The BinaryDiff verifier requires the signed payload itself to be the production RFC 8785 serialization, not merely schema-equivalent JSON with a valid signature. This gives each semantic predicate one accepted byte representation. With a fixed Ed25519 key, repeated signing of that payload produces identical signature and envelope bytes. ECDSA envelopes remain supported and verifiable, but repeated ECDSA signature bytes are not part of the deterministic-output guarantee.
BinaryDiffV1 Predicate
Schema Overview
The BinaryDiffV1 predicate payload uses the following structure:
{
"predicateType": "stellaops.binarydiff.v1",
"subjects": [
{
"name": "docker://repo/app@sha256:target...",
"digest": { "sha256": "target..." },
"platform": { "os": "linux", "architecture": "amd64" }
}
],
"inputs": {
"base": { "digest": "sha256:base..." },
"target": { "digest": "sha256:target..." }
},
"findings": [...],
"metadata": { ... }
}
Predicate Fields
| Field | Type | Description |
|---|---|---|
subjects | array | Target image references with digests |
inputs.base | object | Base image reference |
inputs.target | object | Target image reference |
findings | array | Per-binary diff findings |
metadata | object | Tool version, timestamp, config |
Finding Structure
Each finding represents a binary comparison:
{
"path": "/usr/lib/libssl.so.3",
"changeType": "modified",
"binaryFormat": "elf",
"sectionDeltas": [
{ "section": ".text", "status": "modified" },
{ "section": ".rodata", "status": "added" }
],
"confidence": 0.50,
"verdict": "unknown"
}
Verdicts
Current CLI output uses vanilla for unchanged binaries and unknown for modified binaries. Advanced verdict classification (patched/vanilla) is planned for follow-up work.
| Verdict | Meaning | Confidence Threshold |
|---|---|---|
patched | Binary shows evidence of security patch | >= 0.90 |
vanilla | Binary matches upstream/unmodified | >= 0.95 |
unknown | Cannot determine patch status | < 0.90 |
incompatible | Cannot compare (different architecture, etc.) | N/A |
DSSE Attestation
Envelope Structure
{
"payloadType": "stellaops.binarydiff.v1",
"payload": "<base64-encoded predicate>",
"signatures": [
{
"keyid": "...",
"sig": "<base64-encoded signature>"
}
]
}
Signature Algorithm
- CLI output: ECDSA (P-256/384/521) with operator-provided PEM key
- Library support: Ed25519 available via
EnvelopeSignatureService
Rekor Submission
When Rekor is enabled in attestor tooling:
- DSSE envelope is submitted to Rekor transparency log
- Inclusion proof is retrieved
- Rekor metadata is stored in result
{
"rekorLogIndex": 12345678,
"rekorEntryId": "abc123...",
"integratedTime": "2026-01-13T12:00:00Z"
}
Note: stella scan diff does not submit to Rekor; it only emits local DSSE outputs.
Verification
Binary diff attestations can be verified with:
# Attach the DSSE envelope to the image
stella attest attach \
--image docker://repo/app:1.0.1 \
--attestation ./binarydiff.dsse.json
# Verify with cosign (key-based)
cosign verify-attestation \
--type stellaops.binarydiff.v1 \
--key ./keys/binarydiff.pub \
docker://repo/app:1.0.1
# Verify with stella CLI
stella attest verify \
--image docker://repo/app:1.0.1 \
--predicate-type stellaops.binarydiff.v1
Integration Points
VEX Mapping
Binary diff evidence can support VEX claims:
{
"vulnerability": "CVE-2024-1234",
"status": "fixed",
"justification": "vulnerable_code_not_present",
"detail": "Vendor backport applied; evidence in binary diff attestation",
"evidence": {
"attestationRef": "sha256:dsse-envelope-hash...",
"finding": {
"path": "/usr/lib/libssl.so.3",
"verdict": "patched",
"confidence": 0.95
}
}
}
Policy Engine
Policy rules can reference binary diff evidence:
# Accept high-confidence patch verdicts as mitigation
allow contains decision if {
input.binaryDiff.findings[_].verdict == "patched"
input.binaryDiff.findings[_].confidence >= 0.90
decision := {
"action": "accept",
"reason": "Binary diff shows patched code",
"evidence": input.binaryDiff.attestationRef
}
}
SBOM Properties
Section hashes appear in SBOM component properties:
{
"type": "library",
"name": "libssl.so.3",
"properties": [
{"name": "evidence:section:.text:sha256", "value": "abc123..."},
{"name": "evidence:section:.rodata:sha256", "value": "def456..."},
{"name": "evidence:extractor-version", "value": "1.0.0"}
]
}
Configuration
Scanner Options
scanner:
native:
sectionHashes:
enabled: true
algorithms:
- sha256
- blake3 # optional
sections:
- .text
- .rodata
- .data
- .symtab
- .dynsym
maxSectionSize: 104857600 # 100MB limit
CLI Options
See CLI Reference for full option documentation.
Limitations and Future Work
Current Limitations
- ELF only: PE and Mach-O support planned for M2
- Single platform: Multi-platform diff requires multiple invocations
- No function-level analysis: Section-level granularity only
- Confidence scoring: Placeholder scoring only; verdict classifier is minimal
Roadmap
| Milestone | Capability |
|---|---|
| M2 | PE section analysis for Windows containers |
| M2 | Mach-O section analysis for macOS binaries |
| M3 | Vendor backport corpus with curated test fixtures |
| M3 | Function-level diff using DWARF debug info |
| M4 | ML-based verdict classification |
References
- BinaryDiffV1 JSON Schema
- in-toto Attestation Specification
- DSSE Envelope Specification
- ELF Specification
