feat(security): package legitimacy gate against slopsquatting (#3215)
* feat(security): package legitimacy gate against slopsquatting (#2827) GSD's research → plan → execute pipeline had no install-time legitimacy gate: a hallucinated package name that passes `npm view` could flow all the way to `gsd-executor` running `npm install <malicious-pkg>` with no human checkpoint. This PR closes that gap. Changes: - gsd-phase-researcher: runs slopcheck on every recommended package; emits `## Package Legitimacy Audit` table; strips [SLOP] packages; ecosystem-specific verification (pip/npm/cargo); WebSearch-sourced packages tagged [ASSUMED]; ctx7 fallback uses `command -v` guard instead of `npx --yes` - gsd-planner: injects `checkpoint:human-verify` before [ASSUMED]/[SUS] installs; adds T-{phase}-SC STRIDE row to <threat_model> template; ctx7 fallback also uses `command -v` guard - gsd-executor: RULE 3 excludes package installs from auto-fix; failed installs surface as checkpoints, never silent substitutions - tests/package-legitimacy-gate.test.cjs: 24 structural assertions covering the full gate (node:test + node:assert, no raw .includes()) - docs: USER-GUIDE, COMMANDS, ARCHITECTURE updated with gate description - .changeset: Security fragment for v1.51 release notes Closes #2827 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: expand Package Legitimacy Gate documentation Add full user-facing depth to the gate docs across USER-GUIDE, COMMANDS, and ARCHITECTURE: - USER-GUIDE: rewrite gate section with concrete RESEARCH.md/PLAN.md examples, slopcheck verdict table, [ASSUMED] WebSearch tagging explanation, slopcheck-unavailable troubleshooting, and graceful degradation behavior - COMMANDS.md: expand /gsd-plan-phase gate note with verdict bullets; add install-failure checkpoint behavior to /gsd-execute-phase - ARCHITECTURE.md: expand gate section with threat model rationale, layer table, claim provenance integration, ecosystem coverage, and graceful degradation semantics Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): harden package legitimacy checkpoint semantics * fix(planner): satisfy size gates and tighten package gate wording --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -433,7 +433,11 @@ ui-phase → UI-SPEC.md (design contract, optional)
|
||||
plan-phase
|
||||
├── Research gate (blocks if RESEARCH.md has unresolved open questions)
|
||||
├── Phase Researcher → RESEARCH.md
|
||||
│ └── Package Legitimacy Gate: slopcheck on every package; [SLOP] removed,
|
||||
│ [SUS]/[ASSUMED] flagged; Audit table written to RESEARCH.md
|
||||
├── Planner (with reachability check) → PLAN.md files
|
||||
│ └── checkpoint:human-verify injected before [ASSUMED]/[SUS] installs;
|
||||
│ T-{phase}-SC STRIDE row added for install-bearing plans
|
||||
├── Plan Checker → Verify loop (max 3x)
|
||||
├── Requirements coverage gate (REQ-IDs → plans)
|
||||
└── Decision coverage gate (CONTEXT.md `<decisions>` → plans, BLOCKING — #2492)
|
||||
@@ -653,6 +657,30 @@ Debounce: 5 tool uses between repeated warnings. Severity escalation (WARNING→
|
||||
- Missing bridge files handled gracefully (subagents, fresh sessions)
|
||||
- Context monitor is advisory — never issues imperative commands that override user preferences
|
||||
|
||||
### Package Legitimacy Gate (v1.51)
|
||||
|
||||
The researcher → planner → executor pipeline includes a supply-chain gate against slopsquatting (AI-hallucinated package names pre-registered with malicious post-install scripts).
|
||||
|
||||
**Threat model:** GSD automates the full path from "researcher names a package" to "executor runs `npm install`". A hallucinated name that passes `npm view` (proving only registration, not legitimacy) would previously flow through undetected. ~20% of AI-generated package references are hallucinated; ~43% of those names recur consistently across prompts, making pre-registration economically viable for attackers.
|
||||
|
||||
**Gate layers:**
|
||||
|
||||
| Layer | Component | Action |
|
||||
|-------|-----------|--------|
|
||||
| Research | `gsd-phase-researcher` | Runs `slopcheck install <pkgs> --json`; writes `## Package Legitimacy Audit` table to RESEARCH.md; strips `[SLOP]` packages before RESEARCH.md is written |
|
||||
| Planning | `gsd-planner` | Reads Audit table; inserts `checkpoint:human-verify` before any `[ASSUMED]` or `[SUS]` install task; adds `T-{phase}-SC` STRIDE supply-chain row to `<threat_model>` |
|
||||
| Execution | `gsd-executor` | RULE 3 excludes package installation from auto-fix scope; failed installs surface as checkpoints, never silent substitutions |
|
||||
|
||||
**Claim provenance integration:** Package names discovered via WebSearch are tagged `[ASSUMED]` (not `[VERIFIED]`) regardless of `npm view` result. This extends the existing `[ASSUMED]` / `[VERIFIED]` / `[CITED]` provenance system by enforcing the provenance tag as a hard gate at the install boundary — `[ASSUMED]` always generates a `checkpoint:human-verify` in PLAN.md.
|
||||
|
||||
**Ecosystem coverage:** The researcher uses registry-specific verification commands — `npm view` (Node), `pip index versions` (Python), `cargo search` (Rust) — rather than a single generic check. This catches cross-ecosystem hallucination (~9% rate documented in 2025 USENIX research).
|
||||
|
||||
**Graceful degradation:** If `slopcheck` is unavailable, every recommended package is tagged `[ASSUMED]` and gated with a checkpoint. Research and planning proceed; the system never hard-fails on a missing tool dependency.
|
||||
|
||||
**External dependency:** `slopcheck` (MIT, pip-installable). If abandoned, the `[ASSUMED]`-gate fallback maintains human-checkpoint coverage.
|
||||
|
||||
---
|
||||
|
||||
### Security Hooks (v1.27)
|
||||
|
||||
**Prompt Guard** (`gsd-prompt-guard.js`):
|
||||
|
||||
@@ -162,6 +162,17 @@ Research, plan, and verify a phase.
|
||||
- With `--research`: force-refresh — re-spawn researcher unconditionally, no prompt.
|
||||
- With `--view`: print existing RESEARCH.md to stdout, no spawn. Errors if RESEARCH.md missing.
|
||||
|
||||
**Package Legitimacy Gate (v1.51):**
|
||||
When the researcher recommends external packages, it runs `slopcheck install <pkg> --json` on each one and writes a `## Package Legitimacy Audit` table to RESEARCH.md recording Registry, Age, Downloads, Source Repo, and slopcheck verdict. Verdicts:
|
||||
|
||||
- `[SLOP]` — package removed from RESEARCH.md entirely; never reaches the planner
|
||||
- `[SUS]` — package flagged; planner inserts `checkpoint:human-verify` before the install task
|
||||
- `[OK]` — package approved; no checkpoint added
|
||||
|
||||
Packages sourced from WebSearch are tagged `[ASSUMED]` (not `[VERIFIED]`) and treated the same as `[SUS]` — they get a human checkpoint before install. If `slopcheck` cannot be installed, every recommended package is tagged `[ASSUMED]` and gated.
|
||||
|
||||
See [Package Legitimacy Gate in the User Guide](USER-GUIDE.md#package-legitimacy-gate-v151) for the full checkpoint format, verdict table, and troubleshooting.
|
||||
|
||||
```bash
|
||||
/gsd-plan-phase 1 # Research + plan + verify phase 1
|
||||
/gsd-plan-phase 3 --skip-research # Plan without research (familiar domain)
|
||||
@@ -227,6 +238,8 @@ Execute all plans in a phase with wave-based parallelization, or run a specific
|
||||
**Prerequisites:** Phase has PLAN.md files
|
||||
**Produces:** per-plan `{phase}-{N}-SUMMARY.md`, git commits, and `{phase}-VERIFICATION.md` when the phase is fully complete
|
||||
|
||||
**Package install failures (v1.51):** If a plan's install step fails, the executor surfaces a `checkpoint:human-verify` and stops. It does not auto-install a similarly-named alternative. This is intentional — silently substituting package names is how slopsquatting spreads. Respond to the checkpoint after verifying the package on its registry page.
|
||||
|
||||
```bash
|
||||
/gsd-execute-phase 1 # Execute phase 1
|
||||
/gsd-execute-phase 1 --wave 2 # Execute only Wave 2
|
||||
|
||||
@@ -721,6 +721,87 @@ The `security.cjs` module scans for known injection patterns (role overrides, in
|
||||
|
||||
---
|
||||
|
||||
### Package Legitimacy Gate (v1.51)
|
||||
|
||||
AI coding tools hallucinate package names. Attackers pre-register those names on npm, PyPI, and crates.io with malicious post-install scripts — a technique called *slopsquatting*. A hallucinated name that passes `npm view` looks legitimate, so it would flow undetected through GSD's research → plan → execute pipeline all the way to `npm install <malicious-pkg>` running on your machine.
|
||||
|
||||
v1.51 adds a three-layer gate that stops this before it reaches your shell.
|
||||
|
||||
#### What you'll see
|
||||
|
||||
**In RESEARCH.md** — every phase that recommends external packages now includes a `## Package Legitimacy Audit` table:
|
||||
|
||||
```markdown
|
||||
## Package Legitimacy Audit
|
||||
|
||||
| Package | Registry | Age | Downloads | Source Repo | slopcheck | Disposition |
|
||||
|---------|----------|-----|-----------|-------------|-----------|-------------|
|
||||
| express | npm | 13 yrs | 100M+/wk | github.com/expressjs/express | [OK] | Approved |
|
||||
| some-new-util | npm | 3 days | 47 | none | [SLOP] | REMOVED |
|
||||
| api-bridge | npm | 6 mo | 1.2k/wk | github.com/user/api-bridge | [SUS] | Flagged |
|
||||
|
||||
**Packages removed due to slopcheck:** some-new-util
|
||||
**Packages flagged as suspicious:** api-bridge — planner will require human verification before install
|
||||
```
|
||||
|
||||
`[SLOP]` packages are removed from RESEARCH.md entirely. They never reach the planner.
|
||||
|
||||
**In PLAN.md** — if a package is tagged `[ASSUMED]` (sourced from WebSearch, not registry-verified) or `[SUS]` (slopcheck suspicious), the plan includes a verification checkpoint *before* the install task:
|
||||
|
||||
```xml
|
||||
<task type="checkpoint:human-verify">
|
||||
<what-built>Package verification required before install</what-built>
|
||||
<how-to-verify>
|
||||
Verify these packages before proceeding:
|
||||
- `api-bridge` [SUS — 6 months old, 1.2k downloads/week, GitHub repo present]
|
||||
Check: https://npmjs.com/package/api-bridge
|
||||
Look for: maintainer history, issue tracker activity, no suspicious install scripts
|
||||
</how-to-verify>
|
||||
<resume-signal>Type "verified" once you've confirmed all packages are legitimate</resume-signal>
|
||||
</task>
|
||||
```
|
||||
|
||||
**During execution** — if an install fails, the executor surfaces a checkpoint and stops. It does not silently try a similarly-named alternative (which could be even more dangerous).
|
||||
|
||||
#### Slopcheck verdicts
|
||||
|
||||
| Verdict | Meaning | GSD action |
|
||||
|---------|---------|------------|
|
||||
| `[OK]` | Package passes all legitimacy checks | Proceeds — no checkpoint added |
|
||||
| `[SUS]` | Suspicious signals (new, low downloads, no source repo, etc.) | Flagged in Audit table; planner adds `checkpoint:human-verify` before install |
|
||||
| `[SLOP]` | High-confidence hallucination or attacker-registered package | Removed from RESEARCH.md; never reaches planner |
|
||||
|
||||
#### Claim provenance and WebSearch packages
|
||||
|
||||
Package names discovered through WebSearch are always tagged `[ASSUMED]` in RESEARCH.md, regardless of whether `npm view` succeeds. A package that exists on the registry is not the same as a package that's safe to install — `npm view` only proves registration, not legitimacy.
|
||||
|
||||
`[ASSUMED]` packages trigger the same `checkpoint:human-verify` gate as `[SUS]` packages. You'll see the checkpoint with a link to the registry page and guidance on what to look for.
|
||||
|
||||
#### If slopcheck isn't installed
|
||||
|
||||
GSD attempts `pip install slopcheck` at research time. If that fails:
|
||||
|
||||
- Every recommended package is tagged `[ASSUMED]`
|
||||
- The planner gates every install with a `checkpoint:human-verify` task
|
||||
- Research and planning complete normally — nothing hard-fails
|
||||
|
||||
This is intentionally stricter than the normal flow: slopcheck unavailability means every package install gets a human checkpoint, which is the safest fallback.
|
||||
|
||||
To install slopcheck manually:
|
||||
|
||||
```bash
|
||||
pip install slopcheck
|
||||
# verify: slopcheck install express --json
|
||||
```
|
||||
|
||||
#### slopcheck dependency
|
||||
|
||||
`slopcheck` is a MIT-licensed Python tool maintained by ToxSec (the researcher who documented the slopsquatting attack surface). It checks packages across npm, PyPI, crates.io, RubyGems, Go modules, Maven, and Packagist using multi-signal heuristics: registry age, download count, source-repo linkage, naming distance to popular packages, and registry-specific suspicion patterns.
|
||||
|
||||
If `slopcheck` is ever unavailable or abandoned, GSD's `[ASSUMED]`-gate fallback ensures you always get a human checkpoint before any install — the system never silently degrades to the pre-v1.51 behavior.
|
||||
|
||||
---
|
||||
|
||||
### Execution Wave Coordination
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user