Skip to content

fix(oci): DIGEST_INVALID errors no longer leak computed hash hex (cloister-667ea6 P2, stacked on #86)#87

Closed
jamestexas wants to merge 1 commit into
feat/blobstore-put-verify-7e631bfrom
feat/oci-error-shape-dont-leak-digests
Closed

fix(oci): DIGEST_INVALID errors no longer leak computed hash hex (cloister-667ea6 P2, stacked on #86)#87
jamestexas wants to merge 1 commit into
feat/blobstore-put-verify-7e631bfrom
feat/oci-error-shape-dont-leak-digests

Conversation

@jamestexas
Copy link
Copy Markdown
Contributor

Stacked on #86. Merge #83#84#85#86 → this.

Closes the P2 free-hash-oracle finding from cloister-667ea6 adversarial review.

What was leaking

PR #83's improved diagnostic added both sha256=<hex> and blake3=<hex> of the body to every DIGEST_INVALID response — turning cloister into a free hash-as-a-service oracle. Both hashes are publicly computable so this isn't a confidentiality break, but it's:

  • Computation amplification (offload hashing to cloister)
  • BLAKE3 disclosure (some OCI-native client toolchains don't carry BLAKE3)

Fix

Keep the error naming WHICH algorithms ran (diagnostics still useful) but drop the hex values:

- digest mismatch: client=sha256:<x> sha256=<computed> blake3=<computed>
+ digest mismatch: client=sha256:<x> body matches neither sha256 nor blake3

Four error sites scrubbed: monolithic upload, chunked-finalize, manifest by-digest ref, manifest Docker-Content-Digest header.

Test plan

  • 4 new cases in oci-registry-push.test.ts §"no hash disclosure" assert the body still names "sha256" and "blake3" but contains no 64-hex string other than the client's own claim
  • Regex-based hex scanner — future regressions fail loudly
  • task lint → 1149/1149 tests pass (was 1145, +4)

🤖 Generated with Claude Code

…uted hash hex (cloister-667ea6 P2)

Adversarial review of cloister-667ea6 (enumeration-oracle-hunter,
dos-resilience-auditor) flagged the DIGEST_INVALID response body as
a free hash-as-a-service oracle: posting bytes with a known-wrong
sha256: claim returned BOTH the computed sha256= AND blake3= of the
caller-controlled body.

Both hashes are publicly computable (the caller could just hash
locally), so the leak isn't a confidentiality break — but it's
computation amplification (offload hashing to cloister), and the
BLAKE3 disclosure is more interesting since some OCI-native client
toolchains don't carry a BLAKE3 library.

Fix: keep the error message naming WHICH algorithms ran (so client
diagnostics aren't useless — "I checked both sha256 and blake3,
neither matched your claim") but drop the hex values.

Four error sites scrubbed:
  - oci-registry.ts:482  monolithic upload digest mismatch
  - oci-registry.ts:607  chunked-finalize digest mismatch
  - oci-registry.ts:662  manifest PUT by-digest ref mismatch
  - oci-registry.ts:683  manifest PUT Docker-Content-Digest header mismatch

Tests: 4 new cases in oci-registry-push.test.ts §"no hash disclosure"
assert that the DIGEST_INVALID body still names "sha256" and "blake3"
as algorithms but contains no 64-hex string OTHER than the client's
own claim (echoing the claim is fine — they already know it). Uses a
strict regex-based hex scanner so future regressions fail loudly.

Verification: task lint → 1149/1149 tests pass (was 1145, +4).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jamestexas
Copy link
Copy Markdown
Contributor Author

Superseded by #90 (consolidated build-cache/v1 storage-key + hardening). Closing to reduce review load.

@jamestexas jamestexas closed this May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant