security-adversarial: detect unpinned npx supply-chain risk in evaluator entrypoints - #19
Draft
ruvnet wants to merge 2 commits into
Draft
security-adversarial: detect unpinned npx supply-chain risk in evaluator entrypoints#19ruvnet wants to merge 2 commits into
ruvnet wants to merge 2 commits into
Conversation
…tor entrypoints Nightly Dream Cycle, 2026-08-18. DEEP=security-adversarial, SCAN=redblue,supply-chain. dream.config.json's own evaluatorEntrypoints.darwin invokes `npx @metaharness/darwin evolve --sandbox mock` with no version pin; npx resolves the registry's `latest` dist-tag fresh on every call and isn't governed by this repo's lockfile. Adds a pure detector (findUnpinnedNpxInvocations) wired into the prompt compiler so every future compiled nightly routine surfaces this before an autonomous agent executes it. Detection only, not remediation (matches ADR-0002's precedent). An independent critic review found real correctness bugs in the first pass (--package= mishandling causing both a false positive and a false negative, a missed npm exec alias, a misleading message on local-path invocations) — fixed and re-verified independently before this commit. Full report: docs/dream-cycle/2026-08-18-security-adversarial-report.md Evaluator: npm test. Baseline (parent 8ce3857) 96/96 passed. Candidate 113/113 passed, 0 regressions, clean build.
#19) ACCEPT — unpinned npx supply-chain detector, npm test 96->113, 0 regressions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nightly Dream Cycle, 2026-08-18. DEEP=security-adversarial, SCAN=redblue,supply-chain. Full report:
docs/dream-cycle/2026-08-18-security-adversarial-report.md. Issue: #18.Hypothesis
Given a compiled nightly routine prompt whose
evaluatorEntrypoints/controlPlaneProbesembed literal shell commands invokingnpx <pkg>with no pinned version, when a pure, deterministic detector classifies each such command as PINNED vs UNPINNED and is wired into thecompilestep to emit a visible warning for every unpinned entrypoint, then every future compiled nightly prompt should surface this known supply-chain exposure automatically, before an autonomous agent executes it — subject to: no change to any existing test, no change to the actual entrypoint commands executed tonight (detection only, not remediation), and the detector must be false-positive/false-negative-free against this repo's realdream.config.json. Frozen before implementation.Candidate
+478/-3 across 5 files (2 new source files, 1 new test file, 1 committed report, 2 small wiring edits). One conceptual change:
packages/compile/src/supplychain.ts(pure detector:findUnpinnedNpxInvocations) + wiring intostep6to9Candidateinpackages/compile/src/index.ts.Evaluation Receipt
Real evaluator:
npm test(vitest, this repo's ownbenchentrypoint).8ce3857)Live end-to-end receipt: recompiling this repo's real
dream.config.jsonwith the candidate adds exactly a 3-line**Supply-chain warning**block namingevaluatorEntrypoints.darwin(its real, unpinnednpx @metaharness/darwinentrypoint) — verified withdiffagainst the pre-candidate compiled output.Baseline
Parent commit
8ce385786faa5e63cc0e7105cc6e96f663a51f07, 96/96 tests passing, clean build.Darwin Lineage
Not run —
DARWIN=not-applicable. Probed live tonight (npx @metaharness/darwin evolve --sandbox mock→ real leaderboard, LIVE), but no evolvable population exists for a single, already-minimal pure detector function — same rationale as 2026-08-13/ADR-0002.Evidence
Reproduced live tonight (grade A, first-hand):
npm view @metaharness/darwinshows version0.9.2, 4 published versions (0.8.3→0.9.2), last published 2026-08-15 (3 days before tonight), single maintainerruvnet, only alatestdist-tag exists. Grade A/B research: OWASP's official NPM Security Cheat Sheet explicitly warnsnpxbypasses the lockfile and to pinnpx pkg@<version>, notnpx pkg@latest; the Shai-Hulud/Miasma npm worm lineage has repeatedly compromised maintainer accounts and self-propagated via fresh malicious publishes since late 2025, most recently 2026-08-04 against a ~127M-weekly-download package family. Full evidence trail with grades in the committed report.Reward-Hack Check
Independent critic (separate agent, not this candidate's author) reviewed the diff firsthand (
git diff, file reads, its ownnpx vitest run) and reported FLAGGED with real correctness bugs, CLEAR of reward-hacking:npx --package=@metaharness/darwin@0.9.2 darwin-evolve(pinned) was incorrectly flagged — the original code checked the bin-name token instead of the--package=value.npx --package=@metaharness/darwin run@1.0(genuinely unpinned) produced zero findings, same root cause.npm exec @metaharness/darwin(npx's own alias, same risk) was never scanned.npx ./scripts/tool.js(local file, no registry involved) was flagged with text claiming it "resolves the registrylatestdist-tag".No gold/threshold/gate/automerge-protected path was touched; the golden snapshot test is untouched (the existing fixture has no
npxentrypoint, so the new code path is exercised only by new, honestly-separate test configs). All 4 bugs fixed inpackages/compile/src/supplychain.ts(extractPackageSpecnow honors--package=/-p/--package <spec>;isLocalOrRemoteSpecexcludes local/git/URL specs; the match now also acceptsnpm exec) and independently re-verified by re-running the critic's exact 4 repro strings directly against the rebuilt code — all four now resolve correctly. 6 new regression tests lock in the fixes.Security Review
No prompt injection surface (no LLM calls in this candidate). No credential exposure, no new filesystem/network I/O — the detector is a pure string-only function over already-loaded config fields. No change to
io.exec/verify-entrypoint's actual shell-exec path; this candidate only adds text to the generated prompt, not to what gets executed.Regression Analysis
0 pre-existing tests modified or removed. All 96 baseline tests still pass unchanged; 17 new tests added (14 pure-detector incl. 6 critic-bug regressions, 3 compiler-wiring).
ADR
None. This is a compile-time detection/warning addition, not a new architectural decision — it extends ADR-0002's "classify, don't silently trust or silently fix" precedent within the existing architecture rather than introducing a new invariant or gate.
Gist
No
gh gist createavailable this session (no gist tool, noghCLI in this environment, same as 2026-08-13). Report committed atdocs/dream-cycle/2026-08-18-security-adversarial-report.mdinstead.GIST=LOCAL.Issue
#18
Witness
Verify:
sha256sum docs/dream-cycle/2026-08-18-security-adversarial-report.md, thenprintf '%s%s' "<that hash>" "8ce385786faa5e63cc0e7105cc6e96f663a51f07" | sha256summust equal the witness above. Confirmed tonight viadream-machine witness verify(✓ VALID).Merge Policy
Draft — human review required. This PR does not carry the
automerge-safelabel: it adds a new compile-time behavior (the compiler now emits an extra warning block whenever a future config has an unpinned entrypoint), which is a judgment call about tonight's own scan finding, not touched by the repo's protected-path list, but still substantive enough to warrant a human read rather than an automatic merge. The session never merges and never applies that label itself.Generated by Claude Code