Skip to content

feat(scanner): reject plugin archive decompression bombs - #1166

Draft
seonghobae wants to merge 5 commits into
feat/claude-plugin-insecure-file-mode-1099from
feat/claude-plugin-decompression-bomb-1099
Draft

seonghobae wants to merge 5 commits into
feat/claude-plugin-insecure-file-mode-1099from
feat/claude-plugin-decompression-bomb-1099

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Successor of #1165 / issue #1099. Does not Close those. Does not steal #1165 setuid/world-writable, #1164 hide-actions/self-modify/goal-escalation, or G-06 #1152. Archive path traversal stays #1135.

Current exact authority

  • stack base: feat/claude-plugin-insecure-file-mode-1099@57905590731b5fb5cb7bf8b5e9bed43241bd5605
  • exact head: 0ef0f7d7f3c63faa822a8cff5a20e76514285da2
  • state: open / Draft

Unique delta

Fail closed when a zip/tar member would expand far beyond compressed size, nest recursively, or exceed the package byte budget in aggregate:

  • tiny deflated member claiming huge uncompressed size (uncompressed/compressed > 100) → claude-plugin-decompression-bomb
  • nested zip-in-zip or tar-in-tar deeper than one archive layer → same class
  • regular in-root members whose ZipInfo.file_size / TarInfo.size sum exceeds _MAX_PACKAGE_BYTES → same class, before extract
  • bomb payloads are not extracted; snippets are path labels, not expanded bytes
  • honest small zip/tar of plugin.json+LICENSE is not this class and still extracts
  • ../escape members stay claude-plugin-archive-path-traversal and are omitted from the byte sum
  • directory members are omitted from the byte sum
  • oversized file-count/byte-count of an already materialized tree stays claude-plugin-oversized-package
  • setuid/world-writable mode bits stay feat(scanner): reject plugin setuid and world-writable modes #1165

Ratio, depth, and budget are explicit: _MAX_ARCHIVE_COMPRESSION_RATIO = 100, _MAX_ARCHIVE_NESTING_DEPTH = 1, _MAX_PACKAGE_BYTES for aggregate admission.

Repair: aggregate extraction admission is GREEN

RED e1b3f397d46dc1caad6ba0e1aed73f40098d0f92 (tests/test_claude_plugin_archive_aggregate_admission.py) proved many individually safe ZIP_STORED/TAR members could exceed _MAX_PACKAGE_BYTES while still extracting. GREEN 0ef0f7d inspects zip/tar metadata only and fails closed when the summed uncompressed size of regular in-root members exceeds the budget, with zero extracted members.

Gate

Keep Draft. Predecessor suite counts do not transfer. Require exact-head Tests/security/SAST/CodeQL and qualifying independent current-head review. Do not merge on robot review alone.

Relates to #1099. Relates to #1165. Relates to #1135.

Current non-force restack — 2026-09-12

This Draft is an ordinary two-parent descendant of prior head 0ef0f7d7f3c63faa822a8cff5a20e76514285da2 and current #1165 head 4714d13ec38d85a4c2f34e9518064b70127753c8. Exact head is 348df03ac25d98d6c3ce31b9073f2428b06cd9e0; exact tree is a105e56ef887525b0ebead212bc26c6f65cdd013. GitHub compare reports 5 ahead / 0 behind and preserves archive ratio/depth/aggregate pre-extraction admission with the current mode, directive, command-rule, and MCP precision lineage. Exact-tree Claude-plugin tests are 311/311; detector/CLI compile and diff checks pass. No hosted workflow or qualifying independent current-head review exists, so this custom-base PR remains Draft. Earlier exact-authority strings are historical evidence only.

Summary:
- RED: zip/tar members with huge uncompressed/compressed ratio stay receipt pass.
- Highly nested zip-in-zip and tar-in-tar stay receipt pass.
- Honest small zip/tar of plugin.json+LICENSE, ../escape traversal, and
  oversized file-count stay negative.

Rationale:
- Issue #1099 lists hostile oversized/decompression-bomb/deep-recursion
  packages as admission fail, distinct from byte/file caps and zip-slip.

Tests:
- tests/test_claude_plugin_decompression_bomb.py (8 fail / 5 pass)
Summary:
- Zip/tar members whose uncompressed/compressed ratio exceeds 100 fail as
  claude-plugin-decompression-bomb.
- Nested zip/tar deeper than one archive layer is the same class.
- Honest small zip/tar of plugin.json+LICENSE, ../escape traversal, and
  oversized file-count stay their classes.
- Bomb payloads are not extracted; snippets are path labels.

Rationale:
- Issue #1099 lists decompression-bomb/deep-recursion as admission fail,
  distinct from byte/file caps and zip-slip.

Tests:
- tests/test_claude_plugin_decompression_bomb.py plus plugin suites 268 passed
- detector statement coverage 2201/2201 on Python 3.13
@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

seonghobae added a commit that referenced this pull request Sep 7, 2026
Summary:
- Snapshot 20:26 UTC records Draft #1166 `90cd031` stacked on #1165.
- Archive ratio >100 or nesting deeper than 1 fail closed.
- Bomb members are not extracted; zip-slip stays #1135.

Rationale:
- #999 is the single writer of the product-technical gap baseline.
- #1099 remaining surfaces stay on stacked successors, not Close.

Tests:
- documentation-only; detector evidence lives on #1166 (2201/2201)
Summary:
- Sum zip ZipInfo.file_size and tar regular TarInfo.size before extract.
- Totals above _MAX_PACKAGE_BYTES fail as claude-plugin-decompression-bomb.
- Traversal members and directories are omitted; payloads are not read.

Rationale:
- Per-member ratio/depth still allowed many safe members to exceed the budget.
- Oversized-package after materialization is too late to bound extraction.

Tests:
- tests/test_claude_plugin_archive_aggregate_admission.py plus plugin suites 275 passed
- detector statement coverage 2238/2238 on Python 3.13
seonghobae added a commit that referenced this pull request Sep 7, 2026
Summary:
- Snapshot 21:03 UTC records Draft #1166 `0ef0f7d` stacked on #1165.
- Aggregate in-root uncompressed bytes fail closed before extract.
- Ratio/depth bombs and zip-slip stay their existing classes.

Rationale:
- #999 is the single writer of the product-technical gap baseline.
- RED `e1b3f39` on the canonical writer is not Close; it is GREEN.

Tests:
- documentation-only; detector evidence lives on #1166 (2238/2238)

Copy link
Copy Markdown
Contributor Author

Keep #1166 Draft stacked on #1165 at 0ef0f7d. Aggregate in-root uncompressed bytes now fail closed before extract (RED e1b3f39 → GREEN). Ratio/depth bombs unchanged. Zip-slip stays #1135. Do not Close #1099 or #1165.

Copy link
Copy Markdown
Contributor Author

Successor Draft #1167 (feat/claude-plugin-policy-provenance-1099 @ 18bb1a0) stacks on this exact head for the #1099 scan-policy provenance bind. Unique delta is policy_provenance plus fail-closed scanner_version / policy-digest verification. Bomb extract budget stays here. Does not Close #1099 or #1166. scan_result=pass is not Noema admission.

seonghobae added a commit that referenced this pull request Sep 7, 2026
Summary:
- Snapshot 21:14 UTC records Draft #1167 `18bb1a0` stacked on #1166.
- Receipt policy_provenance binds scanner release version and policy digest.
- Verify fails closed when those disagree with the running scanner.

Rationale:
- #999 is the single writer of the product-technical gap baseline.
- Noema/macos_utility_packs canaries are not this lane.

Tests:
- documentation-only; detector evidence lives on #1167 (2272/2272)
@seonghobae seonghobae added enhancement New feature or request priority: critical Immediate blocker, P0, urgent deadlock, or critical incident labels Sep 8, 2026 — with ChatGPT Codex Connector

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority: critical Immediate blocker, P0, urgent deadlock, or critical incident

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant