[security] deps: RUSTSEC-2026-0285 (rustls) — l'audit quotidien est rouge depuis le 2026-09-15 #348

Closed
opened 2026-09-22 00:08:00 +00:00 by maximus · 0 comments
Owner

Constat

audit.yml échoue tous les jours depuis le 2026-09-15 06:00 UTC, soit 7 runs consécutifs (run_number 405 → 411). Dernier vert : le 2026-09-14 (run 404). Aucun push sur main dans cette fenêtre — le dernier commit date du 2026-09-13 (97ee3c3), le code n'a pas bougé. C'est une advisory publiée entre-temps.

Extrait du log du run 411 :

Crate:     rustls
Version:   0.23.36
Title:     TLS 1.3 handshake messages incorrectly accepted across encryption level boundaries
Date:      2026-09-14
ID:        RUSTSEC-2026-0285
Severity:  5.3 (medium)
Solution:  Upgrade to >=0.23.45

error: 1 vulnerability found! / warning: 12 allowed warnings found — une seule vulnérabilité, le reste du rapport est la liste habituelle des crates non maintenus.

L'advisory est datée du 09-14 et le run du 09-14 à 06:00 UTC était encore vert : elle est parue après ce tir, et le premier rouge est celui du lendemain. La propagation dans l'advisory-db a donc été plus rapide qu'en #343 (deux jours pour h2).

C'est la deuxième fois que le gate crie sans que personne regarde — 17 jours en #343, 7 ici. L'ADR 0018 a réglé l'alarme permanente, pas l'alarme non regardée.

L'advisory

RUSTSEC-2026-0285 / GHSA-2mjx-qc3c-rqvc — catégorie crypto-failure, CVSS 5.3 medium, vecteur AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N.

Rustls acceptait des messages de poignée de main TLS 1.3 envoyés au mauvais niveau de chiffrement lorsqu'ils suivaient un message de changement de clé dans le même enregistrement — par exemple un EncryptedExtensions en clair empaqueté dans le même enregistrement que le ServerHello. La RFC 8446 §5.1 exige qu'un message de poignée de main ne franchisse pas un changement de clé, et que l'implémentation ferme la connexion par une alerte unexpected_message.

Ce n'est pas un contournement : la transcription reste authentifiée, donc un attaquant en position réseau ne peut ni altérer ni compléter une poignée de main. L'effet pratique est qu'un pair peut envoyer en clair des messages qui devraient être chiffrés sans que rustls refuse la connexion. C'est le même défaut que GO-2026-4340 (CVE-2025-61730) côté Go.

Versions non affectées : < 0.23.13. Corrigé en >= 0.23.45, publiée le 2026-09-14 — le jour même de l'advisory.

Atteignabilité

Vérifiée par la méthode de l'ADR 0018 — cargo tree -i par triple livré, jamais --target all. Arbre identique sur les deux cibles livrées :

rustls 0.23.36 ├── hyper-rustls 0.27.7 ──────────── reqwest 0.13.2 → tauri-plugin-updater 2.10.0 → simpl-result
               ├── rustls-platform-verifier 0.6.2 ─ reqwest 0.13.2
               └── tokio-rustls 0.26.4 ──────────── reqwest 0.13.2

Un seul chemin, plus étroit qu'en #343 : celui de la mise à jour automatique (vérification et téléchargement du binaire). Le reqwest que l'app déclare elle-même (Cargo.toml:43, version 0.12.28) — licence, authentification, cours, rétroaction — passe par hyper-tls → native-tls → openssl, pas par rustls. Ces quatre modules ne sont donc pas sur ce chemin, contrairement à ce qui était vrai pour h2.

Par la règle 1 de .cargo/audit.toml : correctif publié + crate atteignable = advisory à corriger, jamais à supprimer. Aucune entrée n'est à ajouter au fichier des suppressions, et le garde-fou de check-rust.yml reste inchangé (CRATES="rsa").

Correctif

cargo update -p rustls --precise 0.23.45. Diff réel du fichier de verrouillage : 4 lignes, 2 strophes.

crate avant après
rustls 0.23.36 0.23.45
rustls-webpki 0.103.13 0.103.15

666 paquets avant et après, Cargo.toml intouché.

Le mouvement de rustls-webpki n'est pas du collatéral opportuniste, il est requis : rustls 0.23.45 resserre sa borne de ^0.103.5 à ^0.103.14, et 0.103.13 ne la satisfait plus. C'est la même forme que le http ^1 → ^1.1 que la revue de #344 avait relevé sur h2 0.4.19, mais cette fois contraignante. La 0.103.15 (2026-08-21) est un mouvement vers l'avant depuis la 0.103.13 que #310 avait posée pour solder quatre advisories : ces correctifs sont conservés. Non yanked.

La borne aws-lc-rs se resserre aussi (^1.14 → ^1.18), sans effet : le crate est absent du graphe (fournisseur cryptographique non activé).

La dérive windows-sys ne s'est pas déclenchée — et cela corrige la prémisse de #345

#345 énonce que tout bump atteignant le sous-arbre réseau/TLS fait redescendre les 7 pointeurs windows-sys de 0.61.2 vers 0.48/0.52/0.59 — mesuré à l'époque sur -p hyper (les 7 bougent) contre -p anyhow (rien ne bouge).

rustls est au cœur de ce sous-arbre, et pourtant rien n'a bougé : les 6 versions de windows-sys présentes sont identiques avant et après, et un diff sur toutes les lignes mentionnant windows-sys dans le fichier de verrouillage est vide. Le déclencheur est donc plus étroit que « le sous-arbre TLS » — il tient à hyper et à ce qu'il tire, pas à la couche TLS en général. Le corps de #345 est à corriger sur ce point ; sa décision de fond (domicilier la contrainte dans un garde-fou et un ADR) reste entière, puisque c'est précisément l'absence de garde qui oblige à re-mesurer à chaque fois.

Conséquence pratique : pas de strophe écrite à la main ici, contrairement à #344. Cargo a écrit le fichier lui-même, donc les checksums viennent de l'index plutôt que de moi — c'est plus solide que l'édition manuelle qu'avait imposée h2.

Vérifications

  • Contrôle sur le fichier de verrouillage d'avant : cargo-audit 0.22.2 exit 1, error: 1 vulnerability found! sur RUSTSEC-2026-0285 — l'outil local reproduit bien le rouge de la CI, donc le vert obtenu ensuite veut dire quelque chose
  • cargo-audit 0.22.2 sur le fichier corrigé : exit 0, 12 warnings autorisés, zéro vulnérabilité
  • cargo metadata --locked : exit 0, fichier de verrouillage non réécrit
  • Checksums authentifiés par sha256sum des .crate réellement téléchargés, pour les deux crates ; et les lignes Compiling rustls v0.23.45 / Checking rustls-webpki v0.103.15 prouvent que ces archives ont bien été récupérées et compilées — cargo metadata --locked prouve le graphe, pas le checksum (nuance posée par la revue de #344)
  • cargo check --locked : exit 0
  • cargo test --locked : 111 passed, 0 failed
  • Garde-fou des suppressions rejoué à la main : Suppression guard: 2 checks, exit 0, rsa absent des deux cibles, canari tar trouvé

Suite

Après merge, rejouer audit.yml en workflow_dispatch sur main pour prouver le vert plutôt que le déduire du run de PR — l'étape cargo audit de check-rust.yml est continue-on-error: true, un job vert n'y prouve rien.

## Constat `audit.yml` échoue tous les jours depuis le **2026-09-15 06:00 UTC**, soit 7 runs consécutifs (`run_number` 405 → 411). Dernier vert : le 2026-09-14 (run 404). Aucun push sur `main` dans cette fenêtre — le dernier commit date du 2026-09-13 (`97ee3c3`), le code n'a pas bougé. C'est une advisory publiée entre-temps. Extrait du log du run 411 : ``` Crate: rustls Version: 0.23.36 Title: TLS 1.3 handshake messages incorrectly accepted across encryption level boundaries Date: 2026-09-14 ID: RUSTSEC-2026-0285 Severity: 5.3 (medium) Solution: Upgrade to >=0.23.45 ``` `error: 1 vulnerability found!` / `warning: 12 allowed warnings found` — une seule vulnérabilité, le reste du rapport est la liste habituelle des crates non maintenus. L'advisory est datée du 09-14 et le run du 09-14 à 06:00 UTC était encore vert : elle est parue après ce tir, et le premier rouge est celui du lendemain. La propagation dans l'advisory-db a donc été plus rapide qu'en #343 (deux jours pour `h2`). C'est la deuxième fois que le gate crie sans que personne regarde — 17 jours en #343, 7 ici. L'ADR 0018 a réglé l'alarme permanente, pas l'alarme non regardée. ## L'advisory [RUSTSEC-2026-0285](https://rustsec.org/advisories/RUSTSEC-2026-0285) / [GHSA-2mjx-qc3c-rqvc](https://github.com/rustls/rustls/security/advisories/GHSA-2mjx-qc3c-rqvc) — catégorie `crypto-failure`, CVSS 5.3 medium, vecteur `AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N`. Rustls acceptait des messages de poignée de main TLS 1.3 envoyés au mauvais niveau de chiffrement lorsqu'ils suivaient un message de changement de clé dans le même enregistrement — par exemple un `EncryptedExtensions` en clair empaqueté dans le même enregistrement que le `ServerHello`. La RFC 8446 §5.1 exige qu'un message de poignée de main ne franchisse pas un changement de clé, et que l'implémentation ferme la connexion par une alerte `unexpected_message`. **Ce n'est pas un contournement** : la transcription reste authentifiée, donc un attaquant en position réseau ne peut ni altérer ni compléter une poignée de main. L'effet pratique est qu'un pair peut envoyer en clair des messages qui devraient être chiffrés sans que rustls refuse la connexion. C'est le même défaut que [GO-2026-4340](https://pkg.go.dev/vuln/GO-2026-4340) (CVE-2025-61730) côté Go. Versions non affectées : `< 0.23.13`. Corrigé en `>= 0.23.45`, publiée le 2026-09-14 — le jour même de l'advisory. ## Atteignabilité Vérifiée par la méthode de l'[ADR 0018](docs/adr/0018-suppression-advisories-non-atteignables.md) — `cargo tree -i` par triple livré, jamais `--target all`. Arbre identique sur les **deux cibles livrées** : ``` rustls 0.23.36 ├── hyper-rustls 0.27.7 ──────────── reqwest 0.13.2 → tauri-plugin-updater 2.10.0 → simpl-result ├── rustls-platform-verifier 0.6.2 ─ reqwest 0.13.2 └── tokio-rustls 0.26.4 ──────────── reqwest 0.13.2 ``` **Un seul chemin, plus étroit qu'en #343** : celui de la mise à jour automatique (vérification et téléchargement du binaire). Le `reqwest` que l'app déclare elle-même (`Cargo.toml:43`, version 0.12.28) — licence, authentification, cours, rétroaction — passe par `hyper-tls → native-tls → openssl`, pas par rustls. Ces quatre modules ne sont donc pas sur ce chemin, contrairement à ce qui était vrai pour `h2`. Par la **règle 1** de `.cargo/audit.toml` : correctif publié + crate atteignable = advisory à corriger, jamais à supprimer. Aucune entrée n'est à ajouter au fichier des suppressions, et le garde-fou de `check-rust.yml` reste inchangé (`CRATES="rsa"`). ## Correctif `cargo update -p rustls --precise 0.23.45`. Diff réel du fichier de verrouillage : **4 lignes, 2 strophes**. | crate | avant | après | |---|---|---| | `rustls` | 0.23.36 | **0.23.45** | | `rustls-webpki` | 0.103.13 | **0.103.15** | 666 paquets avant et après, `Cargo.toml` intouché. Le mouvement de `rustls-webpki` n'est pas du collatéral opportuniste, il est **requis** : rustls 0.23.45 resserre sa borne de `^0.103.5` à `^0.103.14`, et 0.103.13 ne la satisfait plus. C'est la même forme que le `http ^1 → ^1.1` que la revue de #344 avait relevé sur `h2` 0.4.19, mais cette fois contraignante. La 0.103.15 (2026-08-21) est un mouvement vers l'avant depuis la 0.103.13 que #310 avait posée pour solder quatre advisories : ces correctifs sont conservés. Non *yanked*. La borne `aws-lc-rs` se resserre aussi (`^1.14 → ^1.18`), sans effet : le crate est absent du graphe (fournisseur cryptographique non activé). ## La dérive `windows-sys` ne s'est pas déclenchée — et cela corrige la prémisse de #345 #345 énonce que tout bump atteignant le sous-arbre réseau/TLS fait redescendre les 7 pointeurs `windows-sys` de `0.61.2` vers 0.48/0.52/0.59 — mesuré à l'époque sur `-p hyper` (les 7 bougent) contre `-p anyhow` (rien ne bouge). `rustls` est au cœur de ce sous-arbre, et pourtant **rien n'a bougé** : les 6 versions de `windows-sys` présentes sont identiques avant et après, et un `diff` sur toutes les lignes mentionnant `windows-sys` dans le fichier de verrouillage est vide. Le déclencheur est donc plus étroit que « le sous-arbre TLS » — il tient à `hyper` et à ce qu'il tire, pas à la couche TLS en général. **Le corps de #345 est à corriger sur ce point** ; sa décision de fond (domicilier la contrainte dans un garde-fou et un ADR) reste entière, puisque c'est précisément l'absence de garde qui oblige à re-mesurer à chaque fois. Conséquence pratique : pas de strophe écrite à la main ici, contrairement à #344. Cargo a écrit le fichier lui-même, donc les checksums viennent de l'index plutôt que de moi — c'est plus solide que l'édition manuelle qu'avait imposée `h2`. ## Vérifications - Contrôle sur le fichier de verrouillage d'**avant** : `cargo-audit 0.22.2` exit **1**, `error: 1 vulnerability found!` sur RUSTSEC-2026-0285 — l'outil local reproduit bien le rouge de la CI, donc le vert obtenu ensuite veut dire quelque chose - `cargo-audit 0.22.2` sur le fichier corrigé : exit **0**, 12 warnings autorisés, zéro vulnérabilité - `cargo metadata --locked` : exit 0, fichier de verrouillage **non réécrit** - Checksums authentifiés par `sha256sum` des `.crate` réellement téléchargés, pour les deux crates ; et les lignes `Compiling rustls v0.23.45` / `Checking rustls-webpki v0.103.15` prouvent que ces archives ont bien été récupérées et compilées — `cargo metadata --locked` prouve le graphe, pas le checksum (nuance posée par la revue de #344) - `cargo check --locked` : exit 0 - `cargo test --locked` : **111 passed, 0 failed** - Garde-fou des suppressions rejoué à la main : `Suppression guard: 2 checks, exit 0`, `rsa` absent des deux cibles, canari `tar` trouvé ## Suite Après merge, rejouer `audit.yml` en `workflow_dispatch` **sur `main`** pour prouver le vert plutôt que le déduire du run de PR — l'étape `cargo audit` de `check-rust.yml` est `continue-on-error: true`, un job vert n'y prouve rien.
maximus added the
status:ready
type:security
source:analyste
labels 2026-09-22 00:08:00 +00:00
maximus added
status:approved
and removed
status:ready
labels 2026-09-22 00:23:02 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#348
No description provided.