KEVWire

Security intelligence, with context.

Response snapshot Oct 31, 2026, 01:26 UTC

Back to the wire
Permalink
VulnerabilityGHSA-2wrx-84qj-4pcg

anacrolix torrent has unbounded recursion in the bencode decoder that causes stack-overflow crash and CPU-exhaustion DoS

anacrolix/torrent's bencode decoder (bencode/) applies no limit on the nesting depth of nested dictionaries and lists. Two distinct denial-of-service mechanisms follow from that single root cause, both reachable from a single crafted .

At a glance

Exploited
Not known
Severity
Not scored yet
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: github.com/anacrolix/torrent: 1.61.1-0.20260911233437-76452a2c8a2f. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-2wrx-84qj-4pcg (opens a new tab)

What happened

Summary

anacrolix/torrent's bencode decoder (bencode/) applies no limit on the nesting depth of nested dictionaries and lists. Two distinct denial-of-service mechanisms follow from that single root cause, both reachable from a single crafted .torrent file or from metadata obtained from a peer on a magnet-link/v2 download:

1. Stack-overflow process crash. Decoder.readOneValue recurses once per nesting level with no depth bound. A .torrent whose info value is a list nested a few million levels deep (≈8 MB file) drives the recursion past the 1 GiB goroutine-stack limit and the process dies with an unrecoverable fatal error: stack overflow. 2. Quadratic CPU exhaustion. metainfo.FileTree.

UnmarshalBencode (BitTorrent v2) re-parses each subtree at every level, making parse time grow ~O(n²). A v2 info dict with a ~30,000-level file tree (≈0.2 MB) takes ~66 s to decode; 60,000 levels exceeds 90 s of decode time.

Continue reading

Affected: every application embedding github.com/anacrolix/torrent that ingests attacker-supplied metainfo - the CLI tools (cmd/torrent, cmd/torrent2), any server that opens .torrent files, or any client that accepts metadata from a peer for a magnet/v2 download. No depth limit has ever existed in the decoder.

Vulnerability Details

All file:line references are against the pinned commit 4ad31c5170787215c51c6ddaa54abc06b623c11c.

Root cause - no recursion/depth limit in the bencode decoder

bencode/decode.go implements three independently unbounded recursive parsers. There is no depth counter and no MaxDepth/nesting guard anywhere in bencode/ or metainfo/.

Defect 1 - readOneValue recursion (bencode/decode.go:546-549)

case 'd', 'l':
 // read until there is nothing to read
 for d.readOneValue() {
 } // `metainfo.LoadFromFile` (`client.go:1776` inside `AddTorrentFromFile`), and `TorrentSpec.InfoBytes` -> `setInfoBytesLocked` -> `bencode.Unmarshal(b, &info)` (`torrent.go:638`) - peer-fetched metadata.

For the **remote-peer path** (magnet-link/v2 download), peer-supplied metadata pieces are reassembled and passed to `setInfoBytesLocked` once complete (`torrent.go:1874`). The accepted metadata size is capped at `maxMetadataSize = 16 MiB` (`global.go:18`), which comfortably admits the ≈8 MB Defect-1 payload and the ≈0.2 MB Defect-2 payload, so both defects are reachable from an untrusted peer, not only from a locally-opened `.torrent`.

**Defect 2 - `FileTree.UnmarshalBencode` recursive re-parse (`metainfo/file-tree.go:42-49`)**

go for key, bytes := range dir { var sub FileTree err = sub.UnmarshalBencode(bytes) // 7.5). - Scope (S): Unchanged - the impacted security authority is the embedding process itself. - Confidentiality (C): None - no data disclosure. - Integrity (I): None - no data modification. - Availability (A): High - Defect 1 terminates the process with fatal error: stack overflow (unrecoverable); Defect 2 starves a core for ~66 s+ per 0.2 MB v2 info dict with clean quadratic scaling.

Reproduction Steps

All runs are local-only within the test host; nothing contacts a network.

Environment and single harness

The harness is a single Go program (go test-style) that builds the malicious payload, then decodes it through the same public API the library uses. It reproduces both defects. Set up a temp module and run the two tests separately (Defect 1 crashes the process, so the two defects cannot share one test run):

go mod init torrent_recursion_dos
go mod edit -require github.com/anacrolix/torrent@v1.61.0
go mod edit -replace github.com/anacrolix/torrent=/path/to/your/checkout
go test -run TestDefect1_StackOverflow -v .
go test -run TestDefect2_CPUExhaustion -v .

Harness (torrent_recursion_dos_test.go, placed in a temp module that imports the local clone):

package torrent_recursion_dos

import (
 "bytes"
 "fmt"
 "os"
 "testing"

 "github.com/anacrolix/torrent/bencode"
 "github.com/anacrolix/torrent/metainfo"
)

// buildInfo loops a list (l ... l e ... e) nested `depth` levels, wrapped in a
// valid .torrent: { "info": }.
func buildInfo(depth int, mode byte) []byte {
 var b bytes.Buffer
 b.WriteString("d4:infod")
 for i := 0; i ~66 s
depth=60_000 => >90 s (timeout)

To reproduce defect 1 from a saved file instead of the in-memory harness, generate the payload and open it with any of the shipped tools or the metainfo.Load API. The payload is produced inline by the Go harness above; equivalently, emit the same 8,000,010 bytes as d4:infod + 4,000,000 l + 4,000,000 e + ee:

./cmd/torrent -seed -metainfo ./crash.torrent # crashes

The payload is a single static file; it performs no network I/O, writes nothing, and is a plain non-destructive crash reproducer (a harness, not a weapon).

Recommendations

1. Add a nesting-depth limit to the decoder (recommended, fixes both defects). Thread a depth counter through parseValue / parseDict / parseList / parseValueInterface / parseListInterface / parseDictInterface / readOneValue, and return a SyntaxError when it exceeds a sane bound (e.g. 64). Forward-compatibly, expose it on Decoder like the existing MaxStrLen (bencode/decode.go:21-32). 2.

Make readOneValue length-aware. Apply the same MaxStrLen bound to the io.CopyN(&d.buf, d.r, length) at bencode/decode.go:564 instead of trusting the raw length field, so oversized bulk fields fail as SyntaxError instead of being buffered. 3. Break the O(n²) in FileTree.UnmarshalBencode.

Parse the file tree with an explicit, depth-bounded iterative walk (or a single pass over the raw value) instead of re-running bencode.Unmarshal on every subtree level. The depth bound from (1) already arrests the quadratic growth. 4. Convert fatal overflow into a recoverable error. Guarantee that no input can grow the goroutine stack beyond the runtime limit; the depth bound in (1) achieves this.

Do not rely on `recover

Affected package ranges reported by GitHub: github.com/anacrolix/torrent: < 1.61.1-0.20260911233437-76452a2c8a2f

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-2wrx-84qj-4pcg (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-2wrx-84qj-4pcg, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 30). anacrolix torrent has unbounded recursion in the bencode decoder that causes stack-overflow crash and CPU-exhaustion DoS. https://kevwire.com/record/GHSA-2wrx-84qj-4pcg

MLA

"anacrolix torrent has unbounded recursion in the bencode decoder that causes stack-overflow crash and CPU-exhaustion DoS." KEVWire, 30 Oct. 2026, kevwire.com/record/GHSA-2wrx-84qj-4pcg.

Chicago

KEVWire. "anacrolix torrent has unbounded recursion in the bencode decoder that causes stack-overflow crash and CPU-exhaustion DoS." Last modified October 30, 2026. https://kevwire.com/record/GHSA-2wrx-84qj-4pcg.

Evidence summary (plain text)

anacrolix torrent has unbounded recursion in the bencode decoder that causes stack-overflow crash and CPU-exhaustion DoS (Oct 30, 2026).
anacrolix/torrent's bencode decoder (bencode/) applies no limit on the nesting depth of nested dictionaries and lists. Two distinct denial-of-service mechanisms follow from that single root cause, both reachable from a single crafted .torrent file or from metadata obtained from a peer on a magnet-link/v2 download:

1. Stack-overflow process crash. Decoder.readOneValue recurses once per nesting level with no depth bound.
Sources:
GitHub-reviewed advisory GHSA-2wrx-84qj-4pcg: https://github.com/advisories/GHSA-2wrx-84qj-4pcg
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: GHSA-2wrx-84qj-4pcg.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 31, 2026, 00:50 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail