graceful-handoff/docs/review-2026-06-20.md
Kjell Tore Guttormsen a6f3ad4e93 docs: add full-depth plugin review (2026-06-20)
Grade B — strong git path; one MEDIUM indirect-injection surface in the SessionStart hook. Part of the marketplace-wide review (config-audit v5.4.0 + llm-security + structure + version). Read-only; this file is the only artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ter3E2JSi1Khgmuf2kady8
2026-06-20 09:14:08 +02:00

35 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Plugin review — graceful-handoff (2026-06-20)
> Full-depth review (part of the marketplace-wide sweep; pilot was okr). Tooling: config-audit
> v5.4.0 scanners (from source) + llm-security posture assessor + structure/version checks.
> Read-only; this file is the only artifact.
## Verdict
**Grade B — well-engineered, one real injection surface.** The git commit/push path is the
*strongest* part (no shell-string interpolation, `execFileSync` arrays, `--` pathspec guards,
hardcoded `origin`, no force-push, explicit staging allowlist, push user-gated). One indirect
prompt-injection surface in the SessionStart hook caps the grade.
## Results by dimension
| Dimension | Result |
|-----------|--------|
| config-audit posture | **A** (Hooks B, Feature Coverage F 33 — Feat-Cov expected for a focused plugin) |
| config-audit plugin-health | 1 finding: "CLAUDE.md missing hooks section" — **legitimate** (it ships a hook; document it). |
| llm-security posture | **B** — see findings. Supply-chain: zero third-party deps (Node built-ins only). |
| structure / hygiene | README ✓, CHANGELOG ✓, CLAUDE.md ✓, LICENSE ✓ |
| version consistency | **OK** (gate) |
## Findings
| ID | Severity | Location | Finding |
|----|----------|----------|---------|
| F1 | **Medium** | `hooks/scripts/session-start-load-handoff.mjs:61-80` | On resume/compact the hook walks cwd + 3 ancestors, reads the first `NEXT-SESSION-*.local.md`, and injects its **raw, uncapped** contents into `additionalContext` (wrapped in `<session-handoff>` tags but unsanitized). In a shared/multi-repo tree a planted file becomes trusted continuation instructions — indirect prompt injection. Mitigated: `.local.md` is gitignored (doesn't travel via repo); walk is bounded. **Fix:** cap injected size + document that the handoff file is treated as instructions. Closing this lifts the grade to A. |
| F2 | Low | `stop-context-monitor.mjs:55-63,127-137` | Context-threshold is a size heuristic; inflating the transcript can trip an early auto-commit, but the worst outcome is an extra artifact + a **reversible local commit** (push withheld). Lock file is unauthenticated (feature-DoS only). Completeness only. |
| F3 | Info (false-positive-prone) | `handoff-pipeline.mjs:57-77` | `execSync` with shell in read-only `gitOk()` helpers — **safe**: all command strings are static literals; the only interpolation (`${upstream}`, :72) comes from git's own ref-name output, not user input. Called out so a scanner doesn't double-count it. |
**Positive (no finding):** the git mutation path uses `execFileSync('git', [...])` (no shell), `--`
pathspec separators, hardcoded `origin` + current branch (no arbitrary remote/`--force`/`--no-verify`),
an explicit staging allowlist (never `git add -A`), and array-arg commit messages. Push never
auto-executes (Stop hook spawns `--no-push`). Correct agency boundary.