tauri-apps / tauri-apps/plugins-workspace

RUSTSEC-2026-0195: Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service

Open
#3,473 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
1.8k
Forks
602
Avg merge
4d 14h
Merged PRs (30d)
9

Description

> Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service

| Details | |
| ------------------- | ---------------------------------------------- |
| Package | `quick-xml` |
| Version | `0.37.4` |
| URL | [https://github.com/tafia/quick-xml/issues/970](https://github.com/tafia/quick-xml/issues/970) |
| Date | 2026-06-29 |
| Patched versions | `>=0.41.0` |

`NsReader` resolves namespaces by calling `NamespaceResolver::push` for every
`Start`/`Empty` event *before* the event is returned to the caller. `push`
iterated all `xmlns` / `xmlns:*` attributes on the start tag and, for each one,
appended the prefix bytes to an internal buffer and pushed a `NamespaceBinding`
(32 bytes on 64-bit) to an internal `Vec`, with no upper bound on the number of
declarations.

## Impact

A start tag with `N` namespace declarations drove roughly `3×` the tag's byte
size in `NamespaceResolver` heap, allocated *inside* `quick-xml` before the
`NsReader` consumer ever received the event and could inspect or reject it. A
consumer that bounds its *input* size therefore still cannot bound this
allocation: an `M`-byte start tag yields on the order of `3 × M` bytes of
resolver heap the caller never sees.

On untrusted XML this lets a remote, unauthenticated attacker force large heap
allocations with a single start tag. With several `NsReader`s running
concurrently on independent inputs (a common server pattern), the allocations
stack and can exhaust process memory, causing the operating system to kill the
process (OOM). This was confirmed against a real-world RPKI relying party (NLnet
Labs Routinator), where concurrent RRDP validation workers parsing a crafted
`snapshot.xml` exceeded the memory limit and the process was OOM-killed.

## Affected code paths

Consumers using `NsReader` (which always calls `NamespaceResolver::push` before
yielding `Start`/`Empty`), or calling `NamespaceResolver::push` directly. A plain
`Reader` that does not perform namespace resolution is not affected.

## Remediation

Upgrade to `quick-xml >= 0.41.0`. `NamespaceResolver::push` now rejects a start
tag that declares more than `DEFAULT_MAX_DECLARATIONS_PER_ELEMENT` (256)
namespace bindings, returning the new `NamespaceError::TooManyDeclarations`
instead of allocating without limit. The limit is configurable via
`NamespaceResolver::set_max_declarations_per_element` (use `usize::MAX` to
restore the previous unbounded behavior), and `NsReader::resolver_mut()` is
provided to reach it.

There is no clean workaround for `NsReader` consumers before 0.41.0, as the
allocation happens inside the reader with no configuration knob to cap it.

See [advisory page](https://rustsec.org/advisories/RUSTSEC-2026-0195.html) for additional details.

Contributor guide

Open the contributing guide

Research direction

The payload names no repository file, test, or entry point. Start by locating the dependency declaration for quick-xml and checking whether this workspace uses an affected version; then run the relevant project checks. Done means the workspace no longer relies on quick-xml 0.37.4 or another version below 0.41.0.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.