Repository navigation
fix(backend/copilot): stop refusing sub-agent briefs and to-dos that mention sudo or subprocess - #15562
Conversation
…mention sudo or subprocess The PreToolUse hook matched every allowed CLI built-in's input against a word list (sudo, subprocess, rm -rf, os.system, ...). Only Task, Agent and TodoWrite ever reached it, and they take prose: commands run through the copilot's MCP bash_exec, which skips the scan. So it refused briefs and to-do items while guarding nothing that executes. #15123's allowed-set gate stays the check on built-ins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 EvidenceWhat the real PreToolUse hook decides. This is The inputs, in that order:
Package installs go through Mutations. Local suites on
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## pwuts/copilot-default-deny-cli-tools #15562 +/- ##
=====================================================================
Coverage 85.50% 85.50%
=====================================================================
Files 4875 4875
Lines 375597 375590 -7
Branches 33597 33595 -2
=====================================================================
+ Hits 321139 321155 +16
+ Misses 48784 48769 -15
+ Partials 5674 5666 -8
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
🤖 Resolved:
|
…rity-filter-blocks-sub-agent-briefs-that-mention Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Why / What / How
AutoPilot no longer refuses a sub-agent brief or a to-do item because its text mentions
sudo,subprocess,rm -rf,os.systemor a similar word.Stacked on #15123.
Why: Such a call was refused with "[SECURITY] Input contains a blocked pattern. This is enforced by the platform and cannot be bypassed." The model then rewords the brief and tries again, which costs a turn and teaches it to talk around a security message. Nothing was protected. Words in a brief execute nothing, and the commands themselves already run unscanned through
bash_exec.What: The copilot's pre-tool-use hook no longer scans tool input for words. Commands still run only through the sandboxed
bash_exec. The CLI's own Bash stays blocked. #15123's gate still denies every tool outside the session's allowed set.How: This deletes
DANGEROUS_PATTERNSfromsdk/tool_adapter.py, and the loop in_validate_tool_access(sdk/security_hooks.py) that matched each pattern against the JSON of a tool's input. Only three tools ever reached that loop:Task,AgentandTodoWrite, the allowed CLI built-ins, which take prose and run nothing. The rest never got there:bash_exec,run_capabilityand the skill tools among them, around_validate_tool_access;Read,GlobandGrepreturn from their path check before it.The approval gate never read the list. This lands after #15123 because the scan stops being the last check on a built-in only once that gate denies everything outside the allowed set.
What the real hook decided, before and after, with and without E2B:
bash_exec:sudo pip install requests && npm install left-pad && python -c 'import subprocess; …'Agentbrief: "Check whether deploy.sh calls sudo or subprocess.run"TodoWriteitem: "Replace the sudo subprocess call"ListAgents2, a CLI built-in outside the allowed setChanges 🏗️
DANGEROUS_PATTERNSand the hook's scan over it, with thejsonandreimports only it used.test_dangerous_pattern_blockedandtest_subprocess_pattern_blockedwithtest_prose_naming_a_command_is_allowed. The old tests pinned the scan on a made-upSomeTool. The new one drives the real PreToolUse hook with anAgentbrief, aTaskbrief and aTodoWriteitem.Agents and large language models used
Checklist 📋
For code changes:
copilot/sdk/with Claude Code's ownCLAUDE*variables stripped: 1,560 passed, 4 xfailed, none skipped,cli_builtin_tools_test.pyincluded (2 passed). I also ranutil/architecture_test.pyandblocks/test/test_block.py: 3,699 passed, 84 skipped. Putting the scan back fails the new test 3 of 3. Removing fix(backend/copilot): deny every tool outside the session's allowed set, and fail CI on an unclassified CLI built-in #15123's allowed-set check failstest_tool_outside_allowed_set_denied[ListAgents2]. That test already covers an unlisted CLI built-in, so the case gets no new test. The table above comes from calling the real hook on fix(backend/copilot): deny every tool outside the session's allowed set, and fail CI on an unclassified CLI built-in #15123's head and on this one. This PR's base is a feature branch outside a GitHub stack, so backend CI is dispatched by hand: run 38816249199 on1ca20ac934.🤖 Generated with Claude Code