feat: add tool allowlist, denylist, preset list#83
Conversation
|
Looks good overall, the three-layer resolution logic is clean. One thing missing before merge: Custom tools aren't exempted from filtering. Issue spec says "Custom tools always included regardless of filtering" and the README claims const customTools = this.options.customTools ?? []
return [...tools, ...customTools.map(t => t.toDefinition())]The Minor:
|
|
@JackChen-me I've just addressed the issues you mentioned. Thanks for the review. Btw, I slightly updated resolveTools in the latest commit. However, even before that, it was already exempting custom tools by appending them at the end. |
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.
* fix(tools)!: make built-in tools opt-in (default-deny) 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. * docs: clarify defaultToolPreset excludes coordinator, synthesis, and consensus agents
What
Adds denylist support (disallowedTools) and predefined tool presets (toolPreset) to AgentConfig, and introduces a layered tool resolution system (preset → allowlist → denylist) with validation warnings.
Why
The current default-allow model is too permissive and lacks flexibility. Agents cannot explicitly exclude tools, must manually define full allowlists, and have no built-in safety constraints.
Closes #74
Checklist
npm run lintpassesnpm testpasses