sec: answer the advisory gate's first catch, remove hpke-rs 0.2.0, and clear every yanked dependency #449
Merged
dcharlot
merged 4 commits from 2026-10-24 20:47:02 -04:00
sec/unsound-bumps-2026-10 into main 2026-10-24
jouleclaw: read attribute values with normalized_value, not the deprecated unescape_value
All checks were successful
jouleclaw fabrics / cuda (linux, RTX 4050 + Vulkan loader) (pull_request) Successful in 20s
jouleclaw fabrics / vulkan (linux, RTX 4050 + Vulkan loader) (pull_request) Successful in 20s
jouleclaw fabrics / metal (macOS, Apple GPU) (pull_request) Successful in 1m41s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 7s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 10s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m11s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 2m28s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 1m38s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 3m8s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 14s
standards workspaces build + test / macOS energy backends (pull_request) Has been skipped
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m5s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 2m7s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 10m42s
#443 moved jouleclaw to quick-xml 0.41, which deprecates
Attribute::unescape_value. The OpenVINO IR loader and the Maltego TRX parser
still called it, three times each, so every build that denies warnings (the
macOS energy-backends leg) failed to compile jouleclaw-loader-gguf. Both now
use normalized_value(XmlVersion::Implicit1_0), which unescapes the same way
and also normalizes attribute whitespace as XML 1.0 specifies.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit cfd341b057)
sec: answer the gate's first catch — two constant-time advisories, and pin an allowance to the version it excuses
Some checks failed
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 9s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
jouleclaw fabrics / cuda (linux, RTX 4050 + Vulkan loader) (pull_request) Successful in 17s
jouleclaw fabrics / vulkan (linux, RTX 4050 + Vulkan loader) (pull_request) Successful in 17s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 4m9s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 5m46s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 39s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Failing after 10m26s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Failing after 10m44s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 9m33s
standards workspaces build + test / eoc-rs (eoc/eoc-rs, -p eoc-meter --features cuda, eoc-rs, linux) (pull_request) Successful in 3m13s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 3m37s
jouleclaw fabrics / metal (macOS, Apple GPU) (pull_request) Successful in 1m51s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 2m5s
standards workspaces build + test / smart-byte-rs (smart-byte/smart-byte-rs, smart-byte-rs, linux) (pull_request) Successful in 4m10s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 7m43s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 7m49s
standards workspaces build + test / openpay (openpay, openpay, linux-arm64) (pull_request) Successful in 5m48s
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
The advisory gate from #443 found something on its first real run, two days after landing: RUSTSEC-2026-0385 and -0387, both published 2026-10-23, neither of which existed when the sweep was done. That is the gate doing the job it was added for, so this is the answer rather than a new allowance. ctutils 0.4.2/0.4.3 -> 0.4.4 RUSTSEC-2026-0385, non-constant-time mask generation and `u128` comparisons. Reaches openpay's wallet crates through digest -> hmac/hkdf, so it sits under HMAC on payment paths. Fixed in four lockfiles. crypto-bigint 0.7.3 -> 0.7.6 RUSTSEC-2026-0387, secret-dependent branches in subtraction, zero counting, division and Montgomery multiplication — operations whose whole purpose is to be constant-time. The 0.5.5 line of crypto-bigint cannot follow: elliptic-curve 0.13 pins it, so reaching >=0.7.6 means moving the p256/elliptic-curve stack across openpay, sandbox, wai and jouleclaw. That is an upgrade, not a bump. It is allowed with that reason recorded, on paths that sign and derive keys, so it reads as debt. Writing that allowance exposed a weakness in the check itself: ALLOW was keyed by advisory id alone, so an entry excusing the stuck 0.5.5 line would have gone on excusing the advisory if a patched 0.7.x copy later regressed to an unpatched release — the same shape as sealing by name instead of by digest. An entry may now pin the exact crate/version pairs it covers: "RUSTSEC-...": {"why": "...", "only": ("crypto-bigint 0.5.5",)} Any other version of that crate fails, and a named pair that disappears makes the entry stale, so the pin cannot keep describing a tree that moved. The version-blind string form is kept for reasons that genuinely do not depend on the version, such as a call we never make, and the two forms are documented against each other. The self-test now builds its documents by importing the check's real ALLOW rather than scraping it with grep, so the two cannot drift, and covers the two new failure modes: a version-pinned allowance offered a version it does not name, and one whose named pair is gone. Also moves off every yanked dependency, each a patch bump: chacha20 0.10.0/0.10.1 -> 0.10.2 (a cipher, in six lockfiles), der 0.8.0 -> 0.8.2, spin 0.9.8 -> 0.9.9 and 0.10.0 -> 0.10.1, iroh-blobs 0.101.0 -> 0.101.1. A yank is the author withdrawing a release; none of these needed to stay on one. No yanked dependency remains anywhere in the tree. All 47 lockfiles current; the six affected workspaces check clean and `mls_keying` passes. Co-Authored-By: Claude Opus 5 <[email protected]>
sec: align the MLS dev-dependency stack, removing hpke-rs 0.2.0 and its four advisories
`joule-code-collab` dev-depended on openmls 0.6 / openmls_rust_crypto 0.3 while `joule-moq-mls` runs openmls 0.9.1 / 0.6.0 in production. Two generations apart meant a second, older MLS implementation in the test graph, and with it hpke-rs 0.2.0: RUSTSEC-2026-0071 (nonce reuse in an HPKE context, 9.3), -0070 (incorrect length encoding on KDF export, 8.2), -0069 and -0072 (missing all-zero X25519 shared-secret check). Nothing shipped it — the edge is `[dev-dependencies]` only — but there is no reason to test RFC 9420 against an implementation production does not use, and "it is only in the test graph" is a weaker answer than not having it. Pinning the dev-deps to the production generation removes hpke-rs 0.2.0, hpke-rs-crypto 0.2.0, hpke-rs-rust-crypto 0.2.0 and openmls 0.6.0 outright. One API change: openmls 0.9 takes the crypto backend rather than the whole provider in `export_secret`, which is the call joule-moq-mls already makes. `tests/mls_keying.rs` passes. The four allow-list entries are removed with them, which is the check working as intended: an entry that no longer matches anything fails the run, so an excuse cannot outlive the exposure it was written for. Also corrects two allow-list reasons that overstated the remaining quick-xml exposure. I had recorded the openpay 0.37.5 copy as a live exposure on the ISO 20022 ingestion path. It is not: `open-payments-iso20022 1.0.10` declares quick-xml but never calls it — the crate ships serde-annotated types (3 files, ~2.2k lines, no `quick_xml` reference anywhere) and the parsing is ours, in op-iso20022's codec, which binds the workspace 0.41. The copy is compiled and never executed. The smart-byte 0.39.4 copy parses macOS plists via iroh, not counterparty XML. Co-Authored-By: Claude Opus 5 <[email protected]>
sec: take the three unsoundness fixes that are a patch bump away
`cargo audit` reports 67 warnings the advisory gate deliberately does not fail
on, because maintenance advice would bury the reachable defects. Nine of them
are not maintenance advice though — they are unsoundness, and one is a
use-after-free. Three have a semver-compatible fix:
anyhow 1.0.102 -> 1.0.103 RUSTSEC-2026-0190, unsoundness in
`Error::downcast_mut()`
event-listener 5.4.1 -> 5.4.2 RUSTSEC-2026-0221, `!Send` tags crossing a
thread boundary via `StackSlot`
lru 0.18.0 -> 0.18.2 RUSTSEC-2026-0253, potential
use-after-free from missing panic safety
in `LruCache::pop()`
All three are in smart-byte-rs, which still checks clean.
The remaining six are recorded here rather than left unexplained:
- `im` 15.1.0 (RUSTSEC-2023-0126, aliasing violation in `OrdSet` insertion)
and `sized-chunks` 0.6.5 (RUSTSEC-2026-0255, panic-safety unsoundness in
`Chunk`/`RingBuffer`/`InlineArray` — use-after-free and double-free) have
**no fixed release at all**; both crates are unmaintained.
- `lru` 0.12.5 (RUSTSEC-2026-0002, -0253), `rand` 0.7.3 (RUSTSEC-2026-0097)
and `glib` 0.18.5 (RUSTSEC-2024-0429) need a semver-major move, and all
three are transitive, so the dependent has to move first.
Co-Authored-By: Claude Opus 5 <[email protected]>