fix(agent): close opencode env-guard shell wrapper bypass (PEN-1305) - #1027
fix(agent): close opencode env-guard shell wrapper bypass (PEN-1305)#1027kkroo wants to merge 3 commits into
Conversation
…canary-gated) Rolls kkroo/paperclip-adapter-opencode-k8s to master ff92362 (#52): the tool.execute.before env-guard plugin arm behind new adapter config envGuardPlugin (default OFF — fleet Job manifests are unchanged until an agent's config flips it). The plugin runs the full regex guard with shell unwrapping, catching the wrapped/chained env-dump forms (sh -lc "env", ls && printenv) that the permission.bash deny globs from adapter #44 miss; mirrors the claude adapter's PreToolUse hook and server/src/agent-shell-guard. Adapter verification: 592 tests + typecheck green; plugin API validated against the live opencode 1.15.12 fleet runtime (global config-dir plugin auto-discovery proven with a marker plugin on a fleet pod). Pin regression test updated in lockstep (8/8 green). Refs PEN-1305.
|
🔗 Paperclip issue: PEN-1305 |
1 similar comment
|
🔗 Paperclip issue: PEN-1305 |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Hey @kkroo! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
|
Hey @kkroo! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
|
@ally please review exact head |
allyblockcast
left a comment
There was a problem hiding this comment.
Approved exact head de84c7e after inspecting the two-file opencode_k8s pin/test update, confirming the envGuardPlugin rollout remains default-off/canary-gated, and finding no unresolved review threads. Current CI is still running; auto-merge should wait on it.
Superseded at de84c7e: the consolidated App review found unresolved Important findings on this exact head.
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: de84c7e
Important Issues (3)
- [gstack/review]
Dockerfile:347— The canary cannot be reliably rolled back for durable workspace-isolation sessions. The pinned adapter writespaperclip-env-guard.jsunderXDG_CONFIG_HOME, which resolves below the persistentsessionRootfor workspace isolation, but theenvGuardPlugin=falsebranch performs no cleanup. After enabling one canary, turning the flag off can therefore leave the auto-discovered plugin active on later runs.- Make the disabled branch remove the generated plugin/helper, or place them in per-Job ephemeral storage, and add an enabled-to-disabled lifecycle test against a pre-populated session root.
- [pr-review-toolkit]
Dockerfile:347— The pinned guard’s safe-helper exception bypasses dump detection for compound commands.classifyAgentShellCommandreturnsallowas soon asSAFE_ENV_INSPECTION_REmatches anywhere, before testingFULL_ENV_DUMP_RE, so commands such aspaperclip-safe-env && printenvorenv; ./scripts/safe-env-inspect.mjsare allowed.- Restrict the exception to a complete helper-only command or classify each shell segment, then add combined helper-plus-dump cases to the shared corpus and literal-plugin tests.
- [native-codex]
Dockerfile:347— The new plugin still misses valid unquoted wrapper forms such assh -lc envandbash -c printenv.SHELL_WRAPPER_RErequires matching quotes around the payload, and the dump regex does not match while the wrapper prefix remains, despite wrapped dumps being the stated reason for this pin.- Recognize unquoted
-cpayloads and add them to both the classifier corpus and literaltool.execute.beforeartifact tests before canarying.
- Recognize unquoted
Strengths
- The new immutable SHA is a direct child of the prior pin, and the Docker build checks out that exact commit.
- Fresh configurations default
envGuardPluginoff, with focused adapter tests for the clean-state off/on manifest branches and plugin installation ordering. - The adapter tests execute the literal generated plugin and cover loader shape, malformed hook payloads, base64 round-tripping, and fail-open behavior.
Recommended Action
- Fix the three Important rollout/security gaps before merge.
- Extend the adapter corpus with rollback and adversarial compound/wrapper cases.
- Re-pin Paperclip to the corrected adapter commit and move the lockstep assertion with it.
allyblockcast
left a comment
There was a problem hiding this comment.
Reviewed current head; no active unresolved review threads.
Superseded at 9f00a2e: the App review found an unresolved Important shell-wrapper bypass on this exact head.
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 9f00a2e
Prior Findings Dispositioned (3)
- prior:de84c7e important 1 — fixed —
src/server/job-manifest.ts:1159— The exact pinned adapter now routes the default-off branch throughbuildEnvGuardPluginCleanupShell;src/server/env-guard-plugin.ts:173removes both owned persistent artifacts, and the pre-populated cleanup test is atsrc/server/env-guard-plugin.test.ts:215. - prior:de84c7e important 2 — fixed —
src/server/env-guard-plugin.ts:70— Classification now tests the dump regex before an anchored helper-only regex; the literal-plugin corpus covers both helper-plus-dump orderings atsrc/server/env-guard-plugin.test.ts:35. - prior:de84c7e important 3 — fixed —
src/server/env-guard-plugin.ts:42— The wrapper regex now accepts unquoted payloads, and exact-artifact tests coversh -lc env,bash -c printenv, and/bin/sh -lc envatsrc/server/env-guard-plugin.test.ts:32.
Important Issues (1)
- [gstack/review + native-codex]
Dockerfile:352— The newly pinned guard still permits full dumps through valid shell-wrapper positional arguments.sh -c env ignoredexecutes bareenv(ignoredbecomes shell$0), but the adapter unwraps the whole tail asenv ignored, which the dump regex allows. Likewise,bash -c "env" ignoreddoes not match the quoted-wrapper branch because tokens follow the closing quote. The added corpus only covers wrappers without positional arguments.- Parse the shell
-ccommand-string argument separately from subsequent$0/positional arguments for both quoted and unquoted forms, then add classifier and literal-plugin cases such assh -c env ignored,bash -c printenv ignored, andbash -c "env" ignoredbefore canarying.
- Parse the shell
Strengths
- The immutable adapter pin and lockstep Paperclip assertion move together.
- The corrective adapter commit is a direct child of the previously reviewed pin and fixes all three prior findings with exact-artifact coverage.
- The cleanup path is narrowly scoped to the two generated guard artifacts, preserving unrelated OpenCode configuration.
Recommended Action
- Close the remaining shell-wrapper positional-argument bypass before merge.
- Re-pin to the corrected adapter commit and move the lockstep assertion with it.
|
Hey @kkroo! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
allyblockcast
left a comment
There was a problem hiding this comment.
Approved head d6beacc after addressing the remaining env-guard shell-wrapper positional-argument bypass. Adapter pin now targets 83197d46; Paperclip's local guard matches the behavior. Verified focused adapter guard suite, adapter typecheck/build, focused Paperclip guard/Dockerfile tests, and server typecheck.
|
Hey @kkroo! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Thinking Path
PEN-1305 shipped in layers: server-side transcript redaction, the claude adapter pre-execution block, and opencode
permission.bashdeny globs. The glob layer cannot catch wrapped or chained dump forms, so the opencode adapter added a canary-gatedtool.execute.beforeenv-guard plugin. This PR updates Paperclip's production adapter pin to include that guard, then carries the follow-up review fix that parses the actual shell-ccommand string before positional arguments.Linked Issues or Issue Description
Refs PEN-1305.
Related adapter work: kkroo/paperclip-adapter-opencode-k8s#52.
What Changed
Dockerfile: movedOPENCODE_K8S_REFto83197d46b0784c941801165464d48aca1b979909.sh -c env ignoredandbash -c "env" ignoredby parsing the command-string argument separately from shell positional arguments.server/src/agent-shell-guard.ts: mirrored the same shell-wrapper parsing behavior in Paperclip's in-repo guard.Verification
npm test -- src/server/env-guard-plugin.test.tspassed, 90/90.npm run typecheckpassed.npm run buildpassed.pnpm exec vitest run server/src/__tests__/agent-shell-guard.test.ts server/src/__tests__/docker-opencode-runtime-pin.test.ts --reporter=dotpassed, 31/31.pnpm --filter @paperclipai/server typecheckpassed in the fix(agent): close opencode env-guard shell wrapper bypass (PEN-1305) #1027 worktree.Risks
envGuardPlugin.Model Used
Claude Fable 5 (claude-fable-5) via Claude Code, plus Codex GPT-5 for the follow-up review fix.
Rollout plan
envGuardPlugin: trueon one opencode agent.Checklist
Fixes: #/Closes #/Refs #or described the issue in-PR