GitHub Advisoryadvisory · Go

GHSA-2wrx-84qj-4pcg anacrolix torrent has unbounded recursion in the bencode decoder that causes stack-overflow crash and CPU-exhaustion DoS

MEDIUM Published 2026-10-30 Modified 2026-10-30 Official page ↗
Ecosystem
Go
Packages
github.com/anacrolix/torrent
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
Weaknesses
CWE-407, CWE-674
Reviewed
2026-10-30

Affected packages

• Go github.com/anacrolix/torrent: < 1.61.1-0.20260911233437-76452a2c8a2f → fixed in 1.61.1-0.20260911233437-76452a2c8a2f

Description

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. 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`) ```go 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 bu…

Related

Weakness · CWE (2)

  • CWE-407 Inefficient Algorithmic Complexity weakness
  • CWE-674 Uncontrolled Recursion weakness

References