feat(vuln-scanner): introduce Riva research kernel - #70
Conversation
| set -u | ||
|
|
||
| SHADOW_MODE=0 | ||
| if [ "${SKILL_NAME:-}" = "vuln-scanner" ] && [[ "${SKILL_VAR:-}" == shadow:* || "${SKILL_VAR:-}" == compare:* ]]; then |
There was a problem hiding this comment.
[CRITICAL] Bare shadow and compare selectors are not matched here; include the no-colon forms in this condition. Why it matters: the skill parser accepts those forms and sets KERNEL=shadow, but this workflow leaves the run in write mode with GitHub and disclosure credentials available, violating the comparison-only isolation boundary.
Svector-anu
left a comment
There was a problem hiding this comment.
Verdict: blocked: shadow selector bypasses isolation
Bare shadow/compare runs retain write capabilities and credentials.
Findings (mirrored as inline comments):
- [CRITICAL] scripts/resolve-riva-capabilities.sh:7 — bare shadow selectors miss the isolation branch, so a documented comparison mode retains write tools and credentials.
8666d73 to
7e94c62
Compare
|
Refreshed this PR onto current What I found:
Verification on current head
Recommendation: keep open for human review and merge if the Riva product direction is still desired. I do not recommend closing it as stale or superseded. |
Svector-anu
left a comment
There was a problem hiding this comment.
Verdict: blocked — MCP-server entry point bypasses the new shadow-mode isolation this PR adds (already merged; needs an urgent follow-up fix)
Note: this PR merged at 2026-09-16T13:28:43Z, before this review ran. Posting for traceability — the finding below is live on main right now, not a pre-merge blocker.
Good news first: the previously-flagged critical (memory/logs/2026-09-12.md — bare shadow/compare selector bypassing the read-only guard) is fixed here. scripts/resolve-riva-capabilities.sh now matches bare shadow/compare in addition to the shadow:*/compare:* prefix forms, and commit 7e94c624 adds a regression test (test_riva_shadow_guard.sh) asserting all four selector shapes force SHADOW_MODE=1/SKILL_MODE=read-only. Confirmed by reading the script directly, not just the test.
Findings:
- [CRITICAL] apps/mcp-server/src/skill-executor.ts:111 (
resolveMode) and :306 (env: process.env) — the MCP-server dispatch path resolves capability mode viascripts/skill_mode.shdirectly and never sources the newscripts/resolve-riva-capabilities.sh.vuln-scannerhas nomode:frontmatter, soresolveMode()always returnswrite, and the spawned harness inherits the full ambient environment (env: process.env) with no secret withholding. Runningvuln-scannerwithvar=shadoworvar=comparethrough the MCP server (not GitHub Actions) gets full write tools and every live credential (GH_TOKEN,RESEND_API_KEY, etc.) — the exact isolation this PR hardens on theaeon.ymlpath is entirely absent here. The PR's Safety section ("Riva shadow output is private and non-authoritative", "no disclosure actions are invoked by this change") is false on this entry point, and CLAUDE.md's "behaviour is entry-point-agnostic" contract forapps/mcp-server/apps/webhookdoesn't hold for this feature. Why it matters: an operator or automation triggeringvuln-scanner var=shadow:owner/repovia the MCP server would unknowingly run Riva's "private research" mode with full disclosure authority and secrets, defeating the isolation that is this PR's stated purpose.
Recommend a fast-follow PR that either (a) has apps/mcp-server/src/skill-executor.ts source/call the same resolve-riva-capabilities.sh logic before resolving mode/env, or (b) extracts the shadow-selector check into scripts/skill_mode.sh itself so every dispatch surface (aeon.yml, mcp-server, any future webhook path) shares one enforcement point instead of two independently-maintained copies.
…atch path (#81) pr-review's independent verification of #70 caught this after merge: the shadow/compare selector check that forces read-only + strips disclosure credentials only lived in scripts/resolve-riva-capabilities.sh, which only aeon.yml sources. apps/mcp-server/src/skill-executor.ts resolves capability mode straight from scripts/skill_mode.sh with no knowledge of the selector, so vuln-scanner var=shadow dispatched through the MCP server got full write tools and the complete ambient environment, including every live credential, defeating the isolation that PR's Safety section claimed held everywhere. Moves the selector check into skill_mode.sh itself (is_shadow_selector, one new is-shadow subcommand) so it's a single enforcement point instead of two independently-maintained copies, per the review's own recommendation. resolve-riva-capabilities.sh now delegates to it instead of duplicating the pattern. skill-executor.ts threads the runtime var into resolveMode and, when it resolves as a shadow run, strips the same credential set aeon.yml already withholds before spawning the harness. Verified: all 5 existing Riva test files still pass unchanged, the shell logic produces identical output to the old inline check for every existing selector shape, and the new is-shadow path is exercised directly for both positive and negative cases (right skill/wrong skill, right var/wrong var). No test harness exists yet for apps/mcp-server/src itself; typecheck passes but the TS-side fix isn't covered by an automated regression test.
Summary
Introduce Riva as a focused, scan-time vulnerability-research kernel while preserving vuln-scanner's existing mission and operational authority.
Changes
skills/vuln-scanner/riva.mdwith threat-model, invariant, slice, bounded exploration, and evidence contractsSafety
Verification
bash scripts/tests/test_vuln_poc_gate.shbash scripts/tests/test_riva_context.shgit diff --check