@@ -1279,8 +1279,13 @@ export class AIService extends EventEmitter {
12791279 mcpTools
12801280 ) ;
12811281
1282+ // Apply tool policy FIRST - this must happen before PTC to ensure sandbox
1283+ // respects allow/deny filters. The policy-filtered tools are passed to
1284+ // ToolBridge so the mux.* API only exposes policy-allowed tools.
1285+ const policyFilteredTools = applyToolPolicy ( allTools , toolPolicy ) ;
1286+
12821287 // Handle PTC experiments - add or replace tools with code_execution
1283- let toolsWithPTC = allTools ;
1288+ let tools = policyFilteredTools ;
12841289 if ( experiments ?. programmaticToolCalling || experiments ?. programmaticToolCallingExclusive ) {
12851290 try {
12861291 // Lazy-load PTC modules only when experiments are enabled
@@ -1295,8 +1300,8 @@ export class AIService extends EventEmitter {
12951300 // Console events are not streamed (appear in final result only)
12961301 } ;
12971302
1298- // ToolBridge determines which tools can be bridged into the sandbox
1299- const toolBridge = new ptc . ToolBridge ( allTools ) ;
1303+ // ToolBridge uses policy-filtered tools - sandbox only exposes allowed tools
1304+ const toolBridge = new ptc . ToolBridge ( policyFilteredTools ) ;
13001305
13011306 // Singleton runtime factory (WASM module is expensive to load)
13021307 ptc . runtimeFactory ??= new ptc . QuickJSRuntimeFactory ( ) ;
@@ -1310,22 +1315,19 @@ export class AIService extends EventEmitter {
13101315 if ( experiments ?. programmaticToolCallingExclusive ) {
13111316 // Exclusive mode: code_execution + non-bridgeable tools (web_search, propose_plan, etc.)
13121317 // Non-bridgeable tools can't be used from within code_execution, so they're still
1313- // available directly to the model
1318+ // available directly to the model (subject to policy)
13141319 const nonBridgeable = toolBridge . getNonBridgeableTools ( ) ;
1315- toolsWithPTC = { ...nonBridgeable , code_execution : codeExecutionTool } ;
1320+ tools = { ...nonBridgeable , code_execution : codeExecutionTool } ;
13161321 } else {
1317- // Supplement mode: add code_execution alongside other tools
1318- toolsWithPTC = { ...allTools , code_execution : codeExecutionTool } ;
1322+ // Supplement mode: add code_execution alongside policy-filtered tools
1323+ tools = { ...policyFilteredTools , code_execution : codeExecutionTool } ;
13191324 }
13201325 } catch ( error ) {
1321- // Fall back to base tools if PTC creation fails
1326+ // Fall back to policy-filtered tools if PTC creation fails
13221327 log . error ( "Failed to create code_execution tool, falling back to base tools" , { error } ) ;
13231328 }
13241329 }
13251330
1326- // Apply tool policy to filter tools (if policy provided)
1327- const tools = applyToolPolicy ( toolsWithPTC , toolPolicy ) ;
1328-
13291331 const effectiveMcpStats : MCPWorkspaceStats =
13301332 mcpStats ??
13311333 ( {
0 commit comments