Skip to content

fix(deps): clear RUSTSEC-2026-0285 by bumping rustls to 0.23.45 - #1460

Merged
dekobon merged 1 commit into
mainfrom
fix/rustsec-2026-0285-rustls
Sep 14, 2026
Merged

dekobon merged 1 commit into
mainfrom
fix/rustsec-2026-0285-rustls

Conversation

@dekobon

@dekobon dekobon commented Sep 14, 2026

Copy link
Copy Markdown
Owner

What broke

The cargo-deny job is red on main (run 34870318030, commit 78a11ec) and on PR #1459 (run 34870039784). In both runs cargo-deny is the only failing job — the ci aggregator job then fails because it gates on it.

error[vulnerability]: TLS 1.3 handshake messages incorrectly accepted across encryption level boundaries
    ┌─ /github/workspace/Cargo.lock:241:1
241 │ rustls 0.23.43 registry+https://github.com/rust-lang/crates.io-index
    ├ ID: RUSTSEC-2026-0285
    ├ Solution: Upgrade to >=0.23.45

advisories FAILED, bans ok, licenses ok, sources ok

Neither change is at fault. The advisory was published against a version the lockfile already carried, so the next commit to touch main turned CI red regardless of its content. #1459 inherits the same failure from its base.

The advisory

RUSTSEC-2026-0285 / GHSA-2mjx-qc3c-rqvc: rustls accepted TLS 1.3 handshake messages sent at the wrong encryption level when they followed a key-changing message in the same record — a plaintext EncryptedExtensions packed into the ServerHello record, for example — where RFC 8446 §5.1 requires the connection be terminated with an unexpected_message alert.

The handshake transcript remains authenticated, so a network-position attacker can neither alter nor complete a handshake. The practical effect is that a peer may send in plaintext handshake messages that should have been encrypted, without rustls rejecting the connection. Functionally the same bug as Go's GO-2026-4340 (CVE-2025-61730).

Exposure here is nil. rustls is a dev-only transitive dependency:

rustls v0.23.43
├── hyper-rustls v0.27.9 → reqwest v0.13.4 → jsonschema v0.49.9 → (dev) big-code-analysis
├── rustls-platform-verifier v0.7.0 → reqwest (*)
└── tokio-rustls v0.26.4 → reqwest (*)

No shipped code path negotiates TLS through it, and no published crate's dependency graph changes.

The fix

A lockfile bump to the advisory's minimum fixed release:

 name = "rustls"
-version = "0.23.43"
+version = "0.23.45"

Three notes on why the diff is exactly two lines:

  • The incidental hunk is reverted. cargo update -p rustls also re-resolved tempfile's getrandom edge from 0.4.3 to 0.3.4. That is churn, not a fix: tempfile 3.27.0 requires >=0.3.0, <0.5 and both versions remain in the lock through other dependents. cargo metadata --locked accepts the reverted lockfile without re-resolving, so the minimal form is stable rather than something the next cargo invocation churns back.
  • MSRV is respected. Cargo reported Locking 1 package to latest Rust 1.94 compatible version; the msrv (1.94) job covers it.
  • No pinning test accompanies this, unlike h2/RUSTSEC-2026-0258 in big-code-analysis-web/src/lockfile_tests.rs. That test exists because krates filters h2 0.3.27 out of the graph before cargo-deny's checks run, leaving the advisory gate blind — as deny.toml records. rustls is in the graph and the gate saw it, so a second guard over the same lockfile line would be redundant with a check that already works.

A ### Security entry is added to CHANGELOG.md under Unreleased, matching how the previous advisory clears at 2.1.0 and 2.0.0 were recorded.

Verification

  • cargo deny --log-level warn --manifest-path ./Cargo.toml --all-features check advisories bans licenses sources — CI's exact invocation — exits 0: advisories ok, bans ok, licenses ok, sources ok.
  • make pre-commitBCA_GATE: pass (gate=pre-commit).
  • make lint exits 0 with the changelog edit in place.

Merging this should also clear the cargo-deny leg on #1459 once it picks up main.

The `cargo-deny` job has been red on `main` since 78a11ec, and on PR
#1459, for one reason: `advisories FAILED` against `rustls 0.23.43`.
Every other job in both runs passed, so the failure is not attributable
to either change — the advisory was published against a version the
lockfile already carried, which is why a dependency-free commit turned
CI red.

RUSTSEC-2026-0285: rustls accepted TLS 1.3 handshake messages sent at
the wrong encryption level when they followed a key-changing message in
the same record — a plaintext `EncryptedExtensions` packed into the
`ServerHello` record, for example — where RFC 8446 section 5.1 requires
the connection be terminated with an `unexpected_message` alert. The
handshake transcript remains authenticated, so a network-position
attacker can neither alter nor complete a handshake; the practical
effect is that a peer may send in plaintext handshake messages that
should have been encrypted without rustls rejecting the connection.
Functionally the same bug as Go's GO-2026-4340 (CVE-2025-61730).

`rustls` reaches this workspace only as a dev-only transitive
dependency (`jsonschema` -> `reqwest` -> `hyper-rustls` /
`tokio-rustls` / `rustls-platform-verifier`), so no shipped code path
negotiates TLS through it and no published crate's dependency graph
changes. The fix is therefore a lockfile bump to the advisory's minimum
fixed release, 0.23.45.

The diff is deliberately two lines. `cargo update -p rustls` also
re-resolved `tempfile`'s `getrandom` edge from `0.4.3` to `0.3.4` —
incidental churn, since `tempfile 3.27.0` requires `>=0.3.0, <0.5` and
both versions remain in the lock through other dependents. That hunk is
reverted; `cargo metadata --locked` accepts the result without
re-resolving, so the minimal lockfile is stable rather than something
the next cargo invocation would churn back.

No pinning test accompanies this, unlike `h2`/RUSTSEC-2026-0258 in
`big-code-analysis-web/src/lockfile_tests.rs`. That test exists because
krates filters `h2 0.3.27` out of the graph before cargo-deny's checks
run, leaving the advisory gate blind. `rustls` is in the graph and the
gate saw it — a second guard over the same lockfile line would be
redundant with a check that already works.

Verified: `cargo deny --log-level warn --manifest-path ./Cargo.toml
--all-features check advisories bans licenses sources` (CI's exact
invocation) exits 0 with `advisories ok, bans ok, licenses ok, sources
ok`; `make pre-commit` reports `BCA_GATE: pass (gate=pre-commit)`.
@codecov

codecov Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.98%. Comparing base (78a11ec) to head (11c1350).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1460   +/-   ##
=======================================
  Coverage   97.97%   97.98%           
=======================================
  Files         359      359           
  Lines       93425    93425           
  Branches    92994    92994           
=======================================
+ Hits        91533    91542    +9     
+ Misses       1224     1216    -8     
+ Partials      668      667    -1     
Flag Coverage Δ
python 100.00% <ø> (ø)
rust 97.97% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dekobon
dekobon merged commit 49e23af into main Sep 14, 2026
54 checks passed
dekobon added a commit that referenced this pull request Sep 14, 2026
Brings in #1460 (rustls 0.23.45, clearing RUSTSEC-2026-0285) and #1452
(single-language feature subsets build their tests again).

The only conflict was `CHANGELOG.md`, where both sides inserted at the
top of `### Fixed` — additive on both sides, so both are kept. The
rustls entry merged cleanly into `### Security`.

`.bca-baseline.toml` is `-merge` in `.gitattributes` and would have come
back wholly conflicted had both sides touched it; main did not, so the
branch's regenerated values carry through unchanged. Nothing main brings
in moves a metric: its changes are CI config, a lockfile, a changelog
and a test file.
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