Skip to content

fix(tar-extract): bound pax parsing and enforce strict tar framing (PHARN-18) - #212

Merged
PrzemekGalarowicz merged 1 commit into
mainfrom
claude/bold-archimedes-5czyyn
Sep 24, 2026
Merged

PrzemekGalarowicz merged 1 commit into
mainfrom
claude/bold-archimedes-5czyyn

Conversation

@PrzemekGalarowicz

Copy link
Copy Markdown
Contributor

Problem

  • readPaxKeywords parsed g/x payloads of any size. A 192 KB archive whose payload expands to about 128 MB took ~13 s of CPU and ~1.1 GB of memory. Under a 512 MB heap the process crashed and left the temp clone behind.
  • Framing was lenient:
    • a zero block in the middle of the archive silently dropped the rest of it;
    • a missing end marker, trailing garbage and a missing ustar magic were all accepted;
    • a//b and a/./b segments were caught only by safeJoin.

Fix

  • A g/x payload over 64 KiB is refused on its size field alone, before any parsing. The codeload header is about 52 bytes.
  • After the first zero block, every remaining byte must be zero.
  • An archive with no end-of-archive marker is refused.
  • The header must start with ustar (both POSIX ustar\0 and old GNU ustar are accepted).
  • Empty and . path segments below the root are refused.

Tests

  • 7 cases that the old code accepted are now refused. The codeload-shaped fixture still extracts.
  • Local gates, run as a non-root user on node 22: all green. 1472/1472 tests pass and statement coverage is 97.26%.
  • Pipeline artifacts are in .dev/features/tar-strict-framing/.

Advisory

THREAT-MODEL.md §2 (the list of extractor refusals) should gain these rules. That file is write-protected, so a maintainer has to add them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc


Generated by Claude Code

…HARN-18)

A 192 KB archive whose pax global header inflated to ~128 MB cost ~13 s CPU
and >1 GB RSS to parse (OOM under a 512 MB heap, leaving the temp clone).
Framing was lenient: a zero block mid-archive silently dropped the rest,
a missing end marker, trailing garbage and a missing ustar magic were
accepted, and `a//b` / `a/./b` segments were left to safeJoin.

The extractor now refuses a g/x payload over 64 KiB before parsing it,
requires only zeros after the end marker, refuses a missing marker and a
non-ustar header, and refuses empty/"." segments below the root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc
@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 53d21815-3004-41c9-aab4-81b22e2af51b


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@PrzemekGalarowicz
PrzemekGalarowicz merged commit 0ca29b7 into main Sep 24, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants