Skip to content

fix(release): renew image advisories for v0.23.0 - #791

Merged
jeremi merged 2 commits into
mainfrom
fix/refresh-v023-image-advisories
Aug 20, 2026
Merged

fix(release): renew image advisories for v0.23.0#791
jeremi merged 2 commits into
mainfrom
fix/refresh-v023-image-advisories

Conversation

@jeremi

@jeremi jeremi commented Aug 20, 2026

Copy link
Copy Markdown
Member

The v0.23.0 candidate run stopped in the advisory gate. Two causes: the reviewed whole-image fingerprints still named the v0.22.0 candidate images, and Grype now reports CVE-2026-14456 in libssl3t64, a High finding with no exception.

This renews all three baselines against the v0.23.0 candidate images built from 5c4e28578cf3c632faca77bf9d81cd18e95c635f, and records the reviewed CVE-2026-14456 acceptance.

Security review notes

  • Only application_layer_ids[0] moved in each image. The pinned 21-layer distroless base prefix is unchanged, so runtime_base_changed is not triggered; the OCI process config is unchanged and was re-reviewed against the production contract.
  • Every digest here was recomputed from the candidate images themselves: pulled by digest from ghcr.io, scanned with the versions release-candidate.yml pins (syft v1.45.1, grype v0.114.0, crane v0.21.2), reviewed file digests taken from the exported rootfs. No digest was carried over or invented.
  • The three libc6 acceptances keep their reasoning; their claims were re-verified against the v0.23.0 bytes before the rationale text moved from v0.22.0 to v0.23.0. __isoc23_sscanf is still reached only from fixed-format call sites, the binaries still export no wide-character input path, and no deprecated resolver-printing function is present.
  • CVE-2026-14456 is an unbounded pending-connection queue in the OpenSSL QUIC server path. Debian marks it postponed for Trixie with no fixed version and Grype reports it wont-fix, so a base bump cannot clear it. No workspace crate links OpenSSL: TLS is rustls with aws-lc-rs, the only OpenSSL-adjacent dependency is openssl-probe (a pure-Rust CA-path finder), and each binary declares only libgcc_s.so.1, libm.so.6, libc.so.6 and the loader as NEEDED, with no libssl.so.3 or libcrypto.so.3 name to load dynamically. libssl3t64 ships in the pinned base and no image process opens it.
  • The acceptances use whole_image_fingerprint_equals rather than a closure assertion. All three binaries import dlsym (evidence and relay also dlopen), so executable_closure() reports an open closure and any closure-based assertion would evaluate as unevaluable.
  • All four exceptions in a baseline share one reviewed fingerprint. Layer equality already pins every rootfs byte, including the unused libssl3t64 bytes, so a per-advisory file list would add no evidence and would split the reviewed image identity.
  • Review window keeps the established 14-day cadence: reviewed_at 2026-08-20, expires_at 2026-09-03.

Test change

The checker's live-baseline test grew a second package, so its synthetic Syft model now derives one artifact per exception from the baseline instead of hard-coding libc6, and it evaluates on the baselines' own review date instead of a pinned literal.

Verification

Scans were reproduced locally on linux/amd64 with the pinned scanner versions, then the gate was run exactly as release-candidate.yml runs it, against all three candidate images:

advisory baseline: grype image=sha256:8896bc15... threshold=high findings=15 blocking=4 exceptions=4 invalid=0
advisory baseline: grype image=sha256:94dafa4e... threshold=high findings=15 blocking=4 exceptions=4 invalid=0
advisory baseline: grype image=sha256:bba41cf6... threshold=high findings=15 blocking=4 exceptions=4 invalid=0

Also run and green: python3 -m unittest release/scripts/test_check_advisory_baselines.py (45 tests), test_registry_release.py (68), test_check_release_source_model.py (12), check-release-source-model.sh, registry-release validate release/manifests/registry-stack-beta-34.yaml, products/relay-v2/scripts/check-contracts.sh.

Scope note: this spans release/ and products/relay-v2/security/, matching the precedent set by #776, since the three baselines are renewed as one reviewed set.

The v0.23.0 candidate run stopped in the advisory gate. Two causes: the
reviewed whole-image fingerprints still named the v0.22.0 candidate
images, and Grype now reports CVE-2026-14456 in libssl3t64, a High
finding with no exception.

Renew all three baselines against the v0.23.0 candidate images built
from 5c4e285, and record the reviewed
CVE-2026-14456 acceptance.

Security review notes:

- Only application_layer_ids[0] moved in each image. The pinned
  21-layer distroless base prefix is unchanged, so runtime_base_changed
  is not triggered; the OCI process config is unchanged and was
  re-reviewed against the production contract.
- Every digest here was recomputed from the candidate images
  themselves: the images were pulled by digest from ghcr.io, scanned
  with the versions release-candidate.yml pins (syft v1.45.1, grype
  v0.114.0, crane v0.21.2), and the reviewed file digests were taken
  from the exported rootfs. No digest was carried over or invented.
- The three libc6 acceptances keep their reasoning; their claims were
  re-verified against the v0.23.0 bytes before the rationale text moved
  from v0.22.0 to v0.23.0. __isoc23_sscanf is still reached only from
  fixed-format call sites, the binaries still export no wide-character
  input path, and no deprecated resolver-printing function is present.
- CVE-2026-14456 is an unbounded pending-connection queue in the
  OpenSSL QUIC server path. Debian marks it postponed for Trixie with
  no fixed version and Grype reports it wont-fix, so a base bump cannot
  clear it. No workspace crate links OpenSSL: TLS is rustls with
  aws-lc-rs, the only OpenSSL-adjacent dependency is openssl-probe (a
  pure-Rust CA-path finder), and each binary declares only
  libgcc_s.so.1, libm.so.6, libc.so.6 and the loader as NEEDED with no
  libssl.so.3 or libcrypto.so.3 name to load dynamically. libssl3t64
  ships in the pinned base and no image process opens it.
- The acceptances use whole_image_fingerprint_equals rather than a
  closure assertion. All three binaries import dlsym (evidence and
  relay also dlopen), so executable_closure() reports an open closure
  and any closure-based assertion would evaluate as unevaluable.
- All four exceptions in a baseline share one reviewed fingerprint.
  Layer equality already pins every rootfs byte, including the unused
  libssl3t64 bytes, so a per-advisory file list would add no evidence
  and would split the reviewed image identity.
- The review window keeps the established 14-day cadence:
  reviewed_at 2026-08-20, expires_at 2026-09-03.

The checker's live-baseline test grew a second package, so its
synthetic Syft model now derives one artifact per exception from the
baseline instead of hard-coding libc6, and it evaluates on the
baselines' own review date instead of a pinned literal.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a68349ba3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread products/relay-v2/security/advisory-baseline.json
Comment thread products/relay-v2/security/advisory-baseline.json
Comment thread release/scripts/test_check_advisory_baselines.py Outdated
The live-baseline evaluability test derived its evaluation date from the
maximum reviewed_at across the baseline's own exceptions. That made the
checker's future-dated guard unreachable for the newest exception: a
baseline committed with a future reviewed_at defined the very "today" it
was compared against, so ordinary CI accepted it and only a later
release-candidate run against the real clock would have stopped it.

State the date independently instead, and cover the guard directly.

Security review notes: this restores a release-provenance gate rather
than relaxing one. LIVE_REVIEW_EVALUATION_DATE is now a stated constant
a reviewer moves by hand at each renewal, so a future-dated reviewed_at
fails in ordinary CI. Verified by mutating a live exception's reviewed_at
to 2026-08-25, which now fails the live test with "future-dated
exception: CVE-2026-14456 libssl3t64 3.5.6-1~deb13u2" and passed
silently before. The new test_future_dated_exception_is_invalid covers
the checker path itself. No baseline content, digest, or exception
changes in this commit.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
@jeremi
jeremi merged commit 6be85c7 into main Aug 20, 2026
36 checks passed
@jeremi
jeremi deleted the fix/refresh-v023-image-advisories branch August 20, 2026 07:02
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