{"aliases":[],"categories":["denial-of-service"],"crate":"quick-xml","cves":[],"cvss":0.0,"database_specific":{"severity":"high"},"date":"2026-06-29","deb_packages":[{"crate_name":"bat","deb_name":"bat","version":"0.26.1+ds-2"},{"crate_name":"bmap-rs","deb_name":"bmap-rs","version":"0.2.3-1"},{"crate_name":"broot","deb_name":"broot","version":"1.60.2+ds-1"},{"crate_name":"czkawka-cli","deb_name":"czkawka-cli","version":"12.0.2-2"},{"crate_name":"czkawka-gui","deb_name":"czkawka-gui","version":"12.0.2-1"},{"crate_name":"doxx","deb_name":"doxx","version":"0.1.4+ds-1"},{"crate_name":"eza","deb_name":"eza","version":"0.23.5-5"},{"crate_name":"feluda","deb_name":"feluda","version":"1.17.0-2"},{"crate_name":"grcov","deb_name":"grcov","version":"0.10.7-2"},{"crate_name":"inquest","deb_name":"inquest","version":"0.3.6-1"},{"crate_name":"quick-xml","deb_name":"librust-quick-xml-dev","version":"0.38.4-1+b1"},{"crate_name":"numbat-cli","deb_name":"numbat","version":"1.24.0-1"},{"crate_name":"presenterm","deb_name":"presenterm","version":"0.16.1+ds-1"},{"crate_name":"rockusb","deb_name":"rockusb","version":"0.2.0-3+b1"},{"crate_name":null,"deb_name":"ty","version":"0.0.85+ruff0.16.10+ds-2"},{"crate_name":"xh","deb_name":"xh","version":"0.26.3-1"},{"crate_name":"xleak","deb_name":"xleak","version":"0.2.6+dfsg-1+b1"}],"description":"`NsReader` resolves namespaces by calling `NamespaceResolver::push` for every\n`Start`/`Empty` event *before* the event is returned to the caller. `push`\niterated all `xmlns` / `xmlns:*` attributes on the start tag and, for each one,\nappended the prefix bytes to an internal buffer and pushed a `NamespaceBinding`\n(32 bytes on 64-bit) to an internal `Vec`, with no upper bound on the number of\ndeclarations.\n\n## Impact\n\nA start tag with `N` namespace declarations drove roughly `3×` the tag's byte\nsize in `NamespaceResolver` heap, allocated *inside* `quick-xml` before the\n`NsReader` consumer ever received the event and could inspect or reject it. A\nconsumer that bounds its *input* size therefore still cannot bound this\nallocation: an `M`-byte start tag yields on the order of `3 × M` bytes of\nresolver heap the caller never sees.\n\nOn untrusted XML this lets a remote, unauthenticated attacker force large heap\nallocations with a single start tag. With several `NsReader`s running\nconcurrently on independent inputs (a common server pattern), the allocations\nstack and can exhaust process memory, causing the operating system to kill the\nprocess (OOM). This was confirmed against a real-world RPKI relying party (NLnet\nLabs Routinator), where concurrent RRDP validation workers parsing a crafted\n`snapshot.xml` exceeded the memory limit and the process was OOM-killed.\n\n## Affected code paths\n\nConsumers using `NsReader` (which always calls `NamespaceResolver::push` before\nyielding `Start`/`Empty`), or calling `NamespaceResolver::push` directly. A plain\n`Reader` that does not perform namespace resolution is not affected.\n\n## Remediation\n\nUpgrade to `quick-xml >= 0.41.0`. `NamespaceResolver::push` now rejects a start\ntag that declares more than `DEFAULT_MAX_DECLARATIONS_PER_ELEMENT` (256)\nnamespace bindings, returning the new `NamespaceError::TooManyDeclarations`\ninstead of allocating without limit. The limit is configurable via\n`NamespaceResolver::set_max_declarations_per_element` (use `usize::MAX` to\nrestore the previous unbounded behavior), and `NsReader::resolver_mut()` is\nprovided to reach it.\n\nThere is no clean workaround for `NsReader` consumers before 0.41.0, as the\nallocation happens inside the reader with no configuration knob to cap it.","id":"RUSTSEC-2026-0195","keywords":["xml","parser","dos","memory","namespace"],"patched_versions":[">=0.41.0"],"source":"debian_rustsec","title":"Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service","url":"https://github.com/tafia/quick-xml/issues/970"}