Skip to content

feat(scanner): reject plugin postinstall downloads - #1144

Draft
seonghobae wants to merge 2 commits into
feat/claude-plugin-license-mismatch-1099from
feat/claude-plugin-postinstall-download-1099
Draft

feat(scanner): reject plugin postinstall downloads#1144
seonghobae wants to merge 2 commits into
feat/claude-plugin-license-mismatch-1099from
feat/claude-plugin-postinstall-download-1099

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

  • Fail closed when package.json preinstall / install / postinstall downloads or executes an unsigned payload (curl/wget to a file then chmod/exec, curl | sh, unpinned URL install).
  • Reuses claude-plugin-unsigned-executable-download, claude-plugin-pipe-to-shell, and claude-plugin-unpinned-package-install (same CWE-494 causal class) instead of a second regex family. Tests prove package.json lifecycle is now a surface.
  • Negative: package.json plus lockfile with no lifecycle script, or lifecycle echo ok / echo hi only, stays package_install inventory and scan_result=pass. No package.json is unchanged.
  • Detector snippets omit secret literals and raw bidi. LICENSE/NOTICE SPDX mismatch from feat(scanner): fail closed on plugin LICENSE/NOTICE SPDX mismatch #1143 is unchanged.

Successor of #1143 / #1138 / issue #1099. Stacked on feat/claude-plugin-license-mismatch-1099 (e5051ea). Does not Close #1099, #1143, #1142, #1141, #1140, #1139, #1138, #1137, #1136, #1135, #1134, #1129, #1087, #929, #983, #1106, #1036, #1133, or #998. Does not steal G-06 #1133 or #1142 SARIF. Lockfile-only package trees without a postinstall download stay inventory.

Test plan

  • RED then GREEN (tests/test_claude_plugin_postinstall_download.py)
  • Detector statement coverage 1359/1359 with plugin suites
  • Interrogate docstring coverage 85/85 on the detector
  • Existing NOTICE/SPDX mismatch contract retained
  • Exact-head Checks on this head
  • Keep Draft until current-head gates are GREEN

Relates to #1099. Relates to #1143. Relates to #1138.

RED coverage for package.json postinstall/preinstall/install scripts that
curl -o then chmod, pipe to a shell, or install an unpinned URL. echo-only
lifecycle scripts plus a lockfile stay package_install inventory. Relates
to #1099.
Fail closed when package.json preinstall, install, or postinstall downloads
or executes an unsigned payload. Reuse claude-plugin-unsigned-executable-download,
pipe-to-shell, and unpinned-package-install rather than a second regex family.
Lockfile-only trees without a lifecycle download stay package_install inventory.
LICENSE/NOTICE SPDX mismatch is unchanged. Relates to #1099.
@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 13:10 UTC records Draft #1144 `c66dfaf` stacked on #1143.
- package.json install lifecycle downloads fail closed.
- Lockfile-only trees stay package_install inventory.

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 #1144 (1359/1359)
@seonghobae seonghobae added enhancement New feature or request priority: medium Normal-priority or P2 work labels Sep 8, 2026 — with ChatGPT Codex Connector
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: medium Normal-priority or P2 work

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant