diff --git a/src/gateway/http-common.ts b/src/gateway/http-common.ts index 993a3ac36..b7e9c1db4 100644 --- a/src/gateway/http-common.ts +++ b/src/gateway/http-common.ts @@ -25,6 +25,12 @@ export function sendUnauthorized(res: ServerResponse) { }); } +export function sendForbidden(res: ServerResponse, message: string) { + sendJson(res, 403, { + error: { message, type: "forbidden" }, + }); +} + export function sendInvalidRequest(res: ServerResponse, message: string) { sendJson(res, 400, { error: { message, type: "invalid_request_error" }, diff --git a/src/gateway/tools-invoke-http.ts b/src/gateway/tools-invoke-http.ts index fa45bf3dc..663ebd3bb 100644 --- a/src/gateway/tools-invoke-http.ts +++ b/src/gateway/tools-invoke-http.ts @@ -7,6 +7,8 @@ import { resolveGroupToolPolicy, resolveSubagentToolPolicy, } from "../agents/pi-tools.policy.js"; +import { resolveSandboxRuntimeStatus } from "../agents/sandbox.js"; +import { isToolAllowed } from "../agents/sandbox/tool-policy.js"; import { buildPluginToolGroups, collectExplicitAllowlist, @@ -26,6 +28,7 @@ import { authorizeGatewayConnect, type ResolvedGatewayAuth } from "./auth.js"; import { getBearerToken, getHeader } from "./http-utils.js"; import { readJsonBodyOrError, + sendForbidden, sendInvalidRequest, sendJson, sendMethodNotAllowed, @@ -116,6 +119,18 @@ export async function handleToolsInvokeHttpRequest( const sessionKey = !rawSessionKey || rawSessionKey === "main" ? resolveMainSessionKey(cfg) : rawSessionKey; + // Check sandbox policy before proceeding. Sandboxed sessions have restricted tool access. + const sandboxRuntime = resolveSandboxRuntimeStatus({ cfg, sessionKey }); + if (sandboxRuntime.sandboxed) { + if (!isToolAllowed(sandboxRuntime.toolPolicy, toolName)) { + sendForbidden( + res, + `Tool "${toolName}" is blocked by sandbox policy (mode=${sandboxRuntime.mode}, session=${sessionKey})`, + ); + return true; + } + } + // Resolve message channel/account hints (optional headers) for policy inheritance. const messageChannel = normalizeMessageChannel(getHeader(req, "x-moltbot-message-channel") ?? ""); const accountId = getHeader(req, "x-moltbot-account-id")?.trim() || undefined;