Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
dd8f311
test: reproduce unbounded direct SBOM archive parsing
seonghobae Aug 6, 2026
22e8764
test: reach direct archive parser regressions
seonghobae Aug 6, 2026
bb15de9
security: preflight release archives before parsing
seonghobae Aug 6, 2026
89a0512
test: bind direct SBOM compressed archive limit
seonghobae Aug 6, 2026
8a14fd9
docs: document direct SBOM archive bounds
seonghobae Aug 6, 2026
989959e
chore: record direct SBOM archive preflight
seonghobae Aug 6, 2026
dd3f8e7
test: require descriptor-bound SBOM archive reads
seonghobae Aug 6, 2026
e839aa1
security: bind SBOM parsing to preflighted archive
seonghobae Aug 6, 2026
d037f24
docs: document descriptor-bound SBOM verification
seonghobae Aug 6, 2026
01a3159
fix: preserve SBOM hashing contract name
seonghobae Aug 6, 2026
39f601c
test: reproduce CLI symlink and live parser growth bypasses
seonghobae Aug 6, 2026
7debd03
test: make parser-growth RED fixtures lint-clean
seonghobae Aug 6, 2026
eecaaa3
security: live-bound archive parser descriptor
seonghobae Aug 6, 2026
faa3939
docs: document live-bounded archive parsing
seonghobae Aug 6, 2026
f232731
test: pin parser live-read bounds
seonghobae Aug 6, 2026
ecf15d7
fix: cap parser reads to remaining artifact bytes
seonghobae Aug 6, 2026
224e6d2
Merge release/sealed-evidence-preparation into security/bound-sbom-ar…
seonghobae Aug 6, 2026
d5e073f
test: reject unsafe parser offsets and descriptor failures
seonghobae Aug 6, 2026
127e457
security: normalize bounded parser stream state
seonghobae Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
without changing the centrally managed review-agent credential contract.

### Security
- Preflight every direct release-SBOM wheel or source archive as one regular
file with a finite 256 MiB compressed-byte ceiling before ZIP or gzip/tar
parsing, metadata reads, or artifact hashing. Symlinks, directories, devices,
missing paths, and inspection failures now fail through stable non-leaking
errors while existing archive-member and decompression defenses remain intact.
- Canonicalize the public manifest writer's optional `forbidden_root` before any
output-parent creation or output-path access. Missing, non-directory,
symlinked, unresolvable, or otherwise noncanonical roots now fail with one
Expand Down
72 changes: 56 additions & 16 deletions docs/sbom-release-evidence.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,41 @@ No SLSA Build level is claimed merely because an SBOM or attestation exists.
file as untrusted input and never imports EgressWeave. It must:

1. accept only a wheel or gzip source distribution;
2. reject unsafe or duplicate paths, links, devices, excessive member counts,
2. inspect the caller-supplied final release-artifact path without resolving that
final component, require a regular file, enforce a 256 MiB compressed-byte
ceiling, open it without following a final symbolic link where the platform
supports that flag, and require the opened descriptor to retain the accepted
device and inode before any parser;
3. parse and hash only that bound descriptor, keep every parser-visible read and
seek live-bounded by the same 256 MiB ceiling, bracket metadata parsing with
finite SHA-256 reads, and fail if the archive bytes change during verification;
4. reject unsafe or duplicate paths, links, devices, excessive member counts,
ambiguous metadata, oversized metadata, and malformed archives;
3. check the declared wheel metadata size before decompression;
4. read exactly one wheel `METADATA` or root source `PKG-INFO` member;
5. verify package identity, license expression, and complete direct runtime
5. check the declared wheel metadata size before decompression;
6. read exactly one wheel `METADATA` or root source `PKG-INFO` member;
7. verify package identity, license expression, and complete direct runtime
requirement declarations against the reviewed manifest;
6. verify every dependency version, SHA-256, and environment marker against the
8. verify every dependency version, SHA-256, and environment marker against the
executable hash-locked subset in `requirements-ci.txt`, while rejecting
dependency extras that could activate packages outside the reviewed graph;
7. validate identities, SPDX license identifiers, purls, graph references,
9. validate identities, SPDX license identifiers, purls, graph references,
relationships, reachability, and acyclicity;
8. compute the artifact SHA-256 without trusting its filename; and
9. emit sorted UTF-8 CycloneDX 1.7 JSON without timestamps or random identifiers.
10. compute the artifact SHA-256 without trusting its filename; and
11. emit sorted UTF-8 CycloneDX 1.7 JSON without timestamps or random identifiers.

The direct generator normalizes missing, uninspectable, symbolic-link, directory,
device, FIFO, socket, replaced, and other non-regular artifact inputs to
`release artifact is missing or unsafe`. The final artifact component remains
unresolved until no-follow validation binds the accepted path to its descriptor.
Inputs above the compressed-byte ceiling fail with
`release artifact exceeds the compressed-byte safety bound`; the parser-facing
wrapper rechecks the live regular descriptor before and after reads and seeks, so
an initially accepted archive that grows past the ceiling fails before the parser
can consume the expanded input. Bytes that change across the descriptor-bound
metadata pass fail with `release artifact changed during verification`.
Accepted-size archives remain subject to all member-count, path, link/device,
metadata-size, decompression, identity, dependency, and digest controls; the
compressed-input check does not replace those independent defenses.

The root component uses a digest-derived `bom-ref`, preventing different
artifacts from sharing evidence identity. The dependency graph is the union
Expand Down Expand Up @@ -116,14 +138,25 @@ model-modified source under a write credential.
## Threats, failure, and recovery

These controls address omitted inventory, evidence bound to the wrong artifact,
filename substitution, manifest-versus-lock drift, undeclared dependency extras,
mutable dependency resolution, nondeterministic evidence, unsafe archives,
metadata decompression, stale or wrong-workflow attestations, and publication
before exact verification.

They do not detect every compromised upstream source, malicious but correctly
hashed package, license obligation, build-host compromise, or undisclosed
vulnerability. Those risks require provenance, reproducible builds,
filename substitution, path replacement between inspection and parsing,
manifest-versus-lock drift, undeclared dependency extras, mutable dependency
resolution, nondeterministic evidence, unsafe archives, compressed-input resource
exhaustion, metadata decompression, stale or wrong-workflow attestations, and
publication before exact verification.

Descriptor identity, live parser bounds, and digest bracketing close ordinary
final-symlink, pathname-replacement, unbounded-growth, and in-place mutation races
during parsing. They do not convert a writable build host into an immutable-storage
system: a privileged writer able to alter and restore the same inode entirely
between verification observations remains a residual mutable-storage risk. Run
evidence generation from an isolated, read-only exact-artifact directory, and
rely on the later sealed-evidence descriptor, digest, and post-publication checks
before any credential-bearing use. No provenance or SLSA claim follows from these
direct-generator controls.

These controls do not detect every compromised upstream source, malicious but
correctly hashed package, license obligation, build-host compromise, or
undisclosed vulnerability. Those risks require provenance, reproducible builds,
vulnerability management, legal review, and hardened runners.

On any generator, digest, semantic, manifest, lock, or attestation failure,
Expand All @@ -150,6 +183,13 @@ https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attesta
GitHub. (2026). *actions/attest* [Computer software]. GitHub.
https://github.com/actions/attest

MITRE. (2026). *CWE-400: Uncontrolled resource consumption.* Common Weakness
Enumeration. https://cwe.mitre.org/data/definitions/400.html

Python Software Foundation. (n.d.). *zipfile—Work with ZIP archives:
Decompression pitfalls.* Python 3 documentation. Retrieved August 6, 2026, from
https://docs.python.org/3/library/zipfile.html#decompression-pitfalls

Python Packaging Authority. (n.d.). *Core metadata specifications.* Python
Packaging User Guide. Retrieved August 5, 2026, from
https://packaging.python.org/en/latest/specifications/core-metadata/
Expand Down
Loading