RUSTSEC-2026-0429 (CVE-2026-115909)

Vulnerability from osv_rustsec – Published: 2026-10-22 12:00 – Updated: 2026-11-02 09:50 – Source website
VLAI
Summary
zip: `ZipArchive::extract` aborts the process on a symlink entry with a large declared size
Details

ZipArchive::extract() sizes the symlink-target buffer from the uncompressed size declared in the central directory record, before reading a single byte of entry data:

let mut target = Vec::with_capacity(file.size() as usize);

Both inputs are attacker-controlled. ZipFile::size() returns uncompressed_size verbatim from the central directory, widened to a full u64 by a ZIP64 extended-information extra field, and is never cross-checked against the compressed size, the remaining archive length, or any platform-appropriate bound for a symlink target. ZipFile::is_symlink() is decided entirely by the S_IFLNK bit of the external-attributes field.

Vec::with_capacity() is infallible: when the reservation is refused it calls handle_alloc_error() and aborts the process. This is not a Rust panic. It is not caught by catch_unwind(), is unaffected by panic = "unwind", and is not contained by running the call on a worker thread.

A 112-byte archive is sufficient. One Stored entry flagged S_IFLNK with a ZIP64 field declaring uncompressed_size = 2^62 and a zero-byte payload makes extract() fail with:

memory allocation of 4611686018427387904 bytes failed
Aborted (core dumped)          # exit 134

The declared value only needs to exceed the host's address space, not its RAM: Vec::with_capacity() maps address space without touching pages, so resident memory stays flat and the abort happens on the refused reservation itself. Under a ulimit -v cap or a memory-constrained container the threshold drops far enough that a plain 32-bit uncompressed_size with no ZIP64 field suffices.

Applications that extract archives from untrusted input are affected on Unix and Windows targets with default features and no special configuration: upload handling, mail-attachment processing, package and artefact ingestion, backup restore and container-image layer extraction. No confidentiality or integrity property is affected: there is no memory unsafety, no out-of-bounds access, no disclosure and no data corruption.

The fix landed in zip-rs/zip2#984 and shipped in 9.0.0.

For further details see: https://github.com/zip-rs/zip2/security/advisories/GHSA-q7v9-x93c-xqv3


{
  "affected": [
    {
      "database_specific": {
        "categories": [
          "denial-of-service"
        ],
        "cvss": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
        "informational": null
      },
      "ecosystem_specific": {
        "affected_functions": null,
        "affects": {
          "arch": [],
          "functions": [],
          "os": []
        }
      },
      "package": {
        "ecosystem": "crates.io",
        "name": "zip",
        "purl": "pkg:cargo/zip"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.0.0-0"
            },
            {
              "fixed": "9.0.0"
            }
          ],
          "type": "SEMVER"
        }
      ],
      "versions": []
    }
  ],
  "aliases": [
    "CVE-2026-115909",
    "GHSA-q7v9-x93c-xqv3"
  ],
  "database_specific": {
    "license": "CC0-1.0"
  },
  "details": "`ZipArchive::extract()` sizes the symlink-target buffer from the uncompressed\nsize declared in the central directory record, before reading a single byte of\nentry data:\n\n```rust\nlet mut target = Vec::with_capacity(file.size() as usize);\n```\n\nBoth inputs are attacker-controlled. `ZipFile::size()` returns\n`uncompressed_size` verbatim from the central directory, widened to a full `u64`\nby a ZIP64 extended-information extra field, and is never cross-checked against\nthe compressed size, the remaining archive length, or any platform-appropriate\nbound for a symlink target. `ZipFile::is_symlink()` is decided entirely by the\n`S_IFLNK` bit of the external-attributes field.\n\n`Vec::with_capacity()` is infallible: when the reservation is refused it calls\n`handle_alloc_error()` and aborts the process. This is not a Rust panic. It is\nnot caught by `catch_unwind()`, is unaffected by `panic = \"unwind\"`, and is not\ncontained by running the call on a worker thread.\n\nA 112-byte archive is sufficient. One `Stored` entry flagged `S_IFLNK` with a\nZIP64 field declaring `uncompressed_size = 2^62` and a zero-byte payload makes\n`extract()` fail with:\n\n```\nmemory allocation of 4611686018427387904 bytes failed\nAborted (core dumped)          # exit 134\n```\n\nThe declared value only needs to exceed the host\u0027s address space, not its RAM:\n`Vec::with_capacity()` maps address space without touching pages, so resident\nmemory stays flat and the abort happens on the refused reservation itself. Under\na `ulimit -v` cap or a memory-constrained container the threshold drops far\nenough that a plain 32-bit `uncompressed_size` with no ZIP64 field suffices.\n\nApplications that extract archives from untrusted input are affected on Unix and\nWindows targets with default features and no special configuration: upload\nhandling, mail-attachment processing, package and artefact ingestion, backup\nrestore and container-image layer extraction. No confidentiality or integrity\nproperty is affected: there is no memory unsafety, no out-of-bounds access, no\ndisclosure and no data corruption.\n\nThe fix landed in [zip-rs/zip2#984](https://github.com/zip-rs/zip2/pull/984) and\nshipped in 9.0.0.\n\nFor further details see: https://github.com/zip-rs/zip2/security/advisories/GHSA-q7v9-x93c-xqv3",
  "id": "RUSTSEC-2026-0429",
  "modified": "2026-11-02T09:50:37Z",
  "published": "2026-10-22T12:00:00Z",
  "references": [
    {
      "type": "PACKAGE",
      "url": "https://crates.io/crates/zip"
    },
    {
      "type": "ADVISORY",
      "url": "https://rustsec.org/advisories/RUSTSEC-2026-0429.html"
    }
  ],
  "related": [],
  "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": "zip: `ZipArchive::extract` aborts the process on a symlink entry with a large declared size"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.