#3834·zipkin

Zipkin HTTP collector gzip-expanded spans can exhaust JVM heap

Author: skadiscarletCreated Jul 1, 2026Updated Jul 1, 2026
Labelsbug

When the default Zipkin HTTP collector is anonymously exposed, a small wire-size but highly expanded gzip Zipkin v2 spans request can trigger Java heap OOM. In the 1 GiB heap, 2 GiB container retest, a roughly 3.37 MiB gzip request expanded to about 1.356 GiB and caused container exit code 3 plus sustained /health 502.

Technical Details

  • Trigger shape: POST a valid Zipkin v2 JSON span list to /api/v2/spans with Content-Encoding: gzip to amplify decompressed size.
  • Root cause summary: The collector decompresses and parses the complete spans list without an effective default bound on decompressed size, span count, or gzip ratio.
  • Exploitation conditions: HTTP collector is anonymously reachable, gzip is allowed, and decompressed size/span count is not limited before Zipkin decodes the body.
  • Static source: External POST /api/v2/spans or /api/v1/spans body with optional Content-Encoding: gzip
  • Static sink: ZipkinHttpCollector.validateAndStoreSpans aggregates request, UnzippingBytesRequestConverter decodes gzip, Collector.acceptSpans decodes List<Span>

Suggested Remediation

  • Add hard limits for request body size, object count, topic/job/key cardinality, queue length, active thread count, or aggregate retained bytes at the vulnerable entry.
  • Enforce authentication and quota checks before expensive body reads, decompression, JSON/protobuf parsing, image rendering, task creation, or state retention.
  • Add per-IP, per-user, per-token, or per-client rate and resource quotas for anonymous or low-privilege entries.
  • Return 400/413/429 as early as possible and avoid retaining complete request bodies, payloads, or incomplete protocol state after rejection.

Recorded limits or mitigations:

  • Disable external exposure of the Zipkin HTTP collector for untrusted clients.
  • Reject or strictly bound gzip Content-Encoding, decompressed size, span count, per-request body size, and request rate before collector decoding.
  • Ingress or Armeria request-size limits may block larger plain requests, but this 1GiB retest shows gzip decompression can reach heap pressure before an effective decompressed-size rejection.

Not affected or substantially reduced risk when:

  • HTTP collector is disabled or reachable only from trusted instrumentation clients.
  • Authentication, network ACLs, or gateway controls block anonymous POST /api/v2/spans.
  • A front proxy or application filter enforces decompressed-size, span-count, or gzip-ratio limits before Zipkin decodes spans.