Bump h2 to 0.4.16 for RUSTSEC-2026-0258 - #323
Merged
Merged
Conversation
|
`main` is red on `cargo deny check advisories`, and neither of today's two
PRs caused it: RUSTSEC-2026-0258 ("h2 unbounded empty DATA frames",
GHSA-q83h-524g-xf6h) was published after #321 merged green, and h2 0.4.15
is on `main` independently of it. Confirmed by checking `git show
main:Cargo.lock` directly rather than inferring from which PR happened to
go red first.
h2 is the HTTP/2 implementation under hyper/axum/reqwest, i.e. in the
stack sms-gateway serves on, so this is a real denial-of-service surface
rather than a transitive dev-only advisory. The advisory's own solution
is ">=0.4.16"; this is a lockfile-only change, no manifest edit.
One thing in the diff is not the h2 bump and is worth naming rather than
leaving for a reviewer to spot: five unrelated packages had their
`windows-sys` reference re-pointed from 0.61.2 down to 0.52.0/0.59.0/
0.48.0. That is cargo re-resolving, not something this change asked for
--- `--precise 0.4.16` produces byte-identical output to a plain `cargo
update -p h2`, so it cannot be avoided by narrowing the invocation.
It is benign, checked rather than assumed: all four windows-sys versions
were ALREADY present in `main`'s lockfile, so the version set is
identical before and after --- no version entered or left the tree, only
five edges moved between versions already there. `cargo deny check bans`
still passes, which is the gate that would catch a genuine new duplicate.
These crates are `cfg(windows)`-gated and are never compiled for this
project's Linux (distroless) or macOS targets.
Verified: `cargo deny check` -> `advisories ok, bans ok, licenses ok,
sources ok` (was `advisories FAILED`); `cargo check --workspace
--all-targets` clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first commit claimed "the other three lockfiles contain no h2 at all --- checked, not assumed." The claim was false and the check that produced it was broken, which is the more useful half to record. The check ran `grep -A1 '^name = "h2"' <file> || echo "(no h2)"` over a hardcoded list of four paths, one of which --- `sdks/rust/vsms-sdk-rust/ Cargo.lock` --- does not exist. `vsms-sdk-rust` is a member of a workspace rooted at `sdks/rust/`, so its lockfile is `sdks/rust/ Cargo.lock`. grep exits non-zero on a missing file exactly as it does on a file with no match, so the `||` branch printed "(no h2)" for a file that was never read, and a false negative was indistinguishable from a real answer. Two consequences: there are FIVE lockfiles in this tree, not four (`deploy/backup-tool/Cargo.lock` was missing from the list entirely), and `sdks/rust/Cargo.lock` was still on h2 0.4.15. CI caught it --- the `cargo deny` job's second step, `cargo deny on vsms-sdk-rust`, failed on RUSTSEC-2026-0258 while the root workspace passed. Enumerated with `find . -name Cargo.lock` this time rather than a hardcoded list, so a lockfile cannot be missing from the check by being absent from someone's memory of the layout: ./Cargo.lock h2=0.4.16 ./ci/e2e-integration/Cargo.lock h2=none ./deploy/backup-tool/Cargo.lock h2=none ./examples/rust/Cargo.lock h2=none ./sdks/rust/Cargo.lock h2=0.4.15 <- fixed here Same `--precise 0.4.16`, same benign windows-sys re-pointing (two edges this time), same reasoning as the first commit. Also re-verified the `aws-lc-rs` absence claim across all five real lockfiles, since that check shared the identical flaw: absent from every one. The conclusion was right; the check that produced it was not. Verified: `cargo deny check` in sdks/rust/vsms-sdk-rust -> `advisories ok, bans ok, licenses ok, sources ok` (was `advisories FAILED`); `cargo check --locked --all-targets` clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stephane-segning
force-pushed
the
fix-rustsec-2026-0258
branch
from
August 18, 2026 10:24
a58221d to
e85d830
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bumps
h20.4.15→0.4.16to clear RUSTSEC-2026-0258. Lockfile only — no manifest change.Intent
mainis currently red oncargo deny check advisories, and neither of today's two PRs caused it. RUSTSEC-2026-0258 ("h2 unbounded empty DATA frames", GHSA-q83h-524g-xf6h) was published after #321 merged green. Found when #322 — a one-file workflow change that touches no dependency — went red oncargo deny.Confirmed against
maindirectly rather than inferred from which PR happened to fail first:h2is the HTTP/2 implementation under hyper/axum/reqwest — the stacksms-gatewayserves on — so this is a real denial-of-service surface, not a dev-only transitive advisory. The advisory's own stated solution is>=0.4.16.Scope
Two lockfiles:
Cargo.lock(root workspace) andsdks/rust/Cargo.lock.The first commit did only the root one, on the strength of a claim that read "the other three lockfiles contain no
h2at all — checked, not assumed." That claim was false, and the check that produced it was broken — which is the more useful half to record.The check ran
grep -A1 '^name = "h2"' <file> || echo "(no h2)"over a hardcoded list of four paths, one of which —sdks/rust/vsms-sdk-rust/Cargo.lock— does not exist.vsms-sdk-rustis a member of a workspace rooted atsdks/rust/, so its lockfile issdks/rust/Cargo.lock.grepexits non-zero on a missing file exactly as it does on a file with no match, so the||branch printed "(no h2)" for a file that was never read. A false negative was indistinguishable from a real answer.CI caught it: the
cargo denyjob's second step,cargo deny on vsms-sdk-rust, failed on RUSTSEC-2026-0258 while the root workspace passed.Re-enumerated with
find . -name Cargo.lockrather than a hardcoded list, so a lockfile cannot be missing from the check by being absent from someone's memory of the layout — and there turn out to be five, not four:I also re-verified the
aws-lc-rs-absence claim across all five real lockfiles, since that check shared the identical flaw: absent from every one. That conclusion was right; the check that produced it was not.One thing in the diff that is not the h2 bump
Five unrelated packages had their
windows-sysreference re-pointed from0.61.2down to0.52.0/0.59.0/0.48.0. Naming it rather than leaving a reviewer to find it:cargo update -p h2 --precise 0.4.16produces byte-identical output to a plaincargo update -p h2. This is cargo re-resolving, not something the command asked for.windows-sysversions were already present inmain's lockfile — the version set is identical before and after. No version entered or left the tree; five edges moved between versions already there.cargo deny check bansstill passes, which is the gate that would catch a genuine new duplicate. These crates arecfg(windows)-gated and are never compiled for this project's Linux (distroless) or macOS targets.Deliberately NOT done
Cargo.lockto suppress thewindows-syschurn. A hand-edited lockfile is worse than a noisy one.cargo update. This fixes the advisory and nothing else; sweeping the other 64 out-of-date dependencies is a separate, deliberate decision.rsa/Marvin) is untouched — still the documented, time-boxed, reasoneddeny.tomlexception, unaffected by this.Verification
cargo check --workspace --all-targetsclean. The rest — clippy, the full test suite, the live-Postgres suites — is this PR's own CI run; a patch bump to the HTTP/2 layer is exactly the kind of change where "it compiles" is not the interesting signal.Screenshots / Evidence
Terminal output inline above.
Risk Assessment
What breaks if I'm wrong:
h2sits under every HTTP path this project has — the gateway's own axum server,reqwestfor provider calls, andwiremockin tests. A regression in a patch release would surface as connection-level failures, which the live-Postgres suites and thewiremock-backed provider/chaos suites exercise for real over loopback HTTP.Why the risk is low: patch release within
0.4.x, semver-compatible, no manifest change, no API surface touched by this repo directly (nothing here importsh2).The larger risk is not merging it —
mainstays red, which blocks every other PR and trains people to ignore a failingcargo deny.AI Usage Declaration
Claude found the advisory while investigating an unrelated red check, verified it was pre-existing on
mainrather than PR-introduced, applied the bump, and investigated the unexpectedwindows-syschurn to the point of confirming it introduces no new version. Every claim is command output.Reviewer Focus
windows-sysre-pointing is the only thing here that isn't mechanical. I'm satisfied it's inert (identical version set,bans ok, never compiled on our targets) but it is the one part of the diff worth a second opinion.cargo deny-checked at all — the root workspace andvsms-sdk-rust.ci/e2e-integration,examples/rustanddeploy/backup-toolhave no advisory gate. None carriesh2today, so nothing is currently hiding there, but that is luck rather than coverage. Worth its own issue; deliberately not widened here.Checklist
docs/roadmap.mdchecked — no edit needed; this changes no milestone, gate, dependency or decision.windows-sysre-resolution behaviour is captured in the commit message, where it belongs.)