fix(tools)!: make built-in tools opt-in (default-deny)#289
Merged
Conversation
A no-tools agent received every registered built-in, including an unsandboxed bash, on the default path (runAgent, runTeam/runTasks, and the runTeam short-circuit). Tool output flows back to the model provider, so under prompt injection this was a remotely triggerable exec + exfiltration primitive. #83 added the allowlist/preset mechanism but kept default-allow; #264 sandboxed the filesystem tools but left bash unsandboxed; together they opened this. Built-in tools now require a positive grant via tools or toolPreset; with neither, an agent resolves to zero. resolveTools() is the chokepoint and the runner gates execution on the granted set, so a registered-but-ungranted call returns a "not granted" error instead of running. Custom/runtime tools (customTools/addTool) stay available since registration is the grant, and still honor disallowedTools. delegate_to_agent follows the same rule. Same default-deny model #87 enforces for cross-agent context. OrchestratorConfig.defaultToolPreset restores the old allow-all in one line; per-agent tools/toolPreset override it. BREAKING CHANGE: agents relying on implicit built-in tools get none until granted. Restore with defaultToolPreset: 'full', or grant per agent via tools/toolPreset.
JackChen-me
force-pushed
the
security/default-deny-builtin-tools
branch
from
June 7, 2026 15:29
1796bf0 to
6d136a8
Compare
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.
What this fixes
A no-tools agent received every registered built-in, including an unsandboxed
bash, straight from the default path (runAgent,runTeam/runTasks, and therunTeamshort-circuit). No tool config required. Every tool result is appended to the model context and sent to the provider, so under prompt injection this default is a remotely triggerable exec + data-exfiltration primitive. #83 added the allowlist/preset mechanism but kept default-allow; #264 sandboxed the filesystem tools but leftbashunsandboxed; together they opened the hole.Built-in tools are now default-deny, the same model #87 already enforces for cross-agent context: an agent gets a built-in only when it grants one via
toolsortoolPreset.How
resolveTools()is the single chokepoint: notoolPresetand noallowedTools=> zero built-in tools. Preset / allowlist / denylist / framework-rail logic otherwise unchanged.customTools/addTool) stay available since registration is the grant, still honoringdisallowedTools.delegate_to_agentfollows the same rule.OrchestratorConfig.defaultToolPresetrestores the old allow-all in one line; per-agent config overrides it.docs/tool-configuration.md,README.md+README_zh.md,CLAUDE.mdinvariant.Non-goals
Not sandboxing
bash(a shell escapes per-path checks trivially; process isolation is the right boundary, see #264) and not adding a capability taxonomy. Default-deny is the minimal correct form.Migration (breaking)
Agents relying on implicit built-in tools get none until granted. Restore with
defaultToolPreset: 'full'on the orchestrator, or grant per agent viatools/toolPreset.Tests
npm run lint && npm testgreen. Newtests/default-deny-tools.test.tsasserts the standalone, short-circuit, and runTasks paths can't run shell or filesystem tools without a grant (a real-bash sentinel proves non-execution),tools/toolPresetstill grant, custom tools survive,defaultToolPresetrestores plus per-agent override wins, and an ungranteddelegate_to_agentis blocked. Rewrote the three tool-filtering tests that encoded default-allow; added the now-required grant to the trace and abort-signal tests whose intent is "the tool runs".