You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
the execute tool should inherit webfetch permissions #54595
The execute tool currently has fetch available every time. This means an agent that has webfetch disabled can bypass this by running a fetch query in the execute tool.
Thanks for the report. I could reproduce this on 2.0.26 (the latest release, since no version was given), and it still happens on the latest dev (38454c6).
What I did:
Set "permission": { "webfetch": "deny" } in the config.
Had the model call the execute tool with await fetch("http://127.0.0.1:<port>/probe") against a local server that logs requests.
As a control, had it call webfetch directly on the same server.
The fetch inside execute reached the server with no permission prompt or error, while the direct webfetch call was blocked as expected. The recording and screenshot below show it, and the script below reproduces it.
Related: #50771 (with open PR #54510) covers file:// URLs in the same Code Mode fetch getting past the read permission. That fix doesn't cover HTTP requests, so this is a separate issue.
recording.mp4
Reproduction script (drive.ts)
// Repro for #54595: Code Mode `execute` fetch ignores a denied `webfetch` permission.import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"// Local HTTP server that records every request it receives.consthits: string[]=[]constserver=Bun.serve({port: 0,hostname: "127.0.0.1",fetch(req){hits.push(req.url)returnnewResponse("SECRET-FROM-NETWORK")},})consturl=`http://127.0.0.1:${server.port}/probe`exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true},config: {// webfetch is denied for every agentpermission: {webfetch: "deny"},},},({ ui, llm })=>Effect.gen(function*(){yield*ui.screenshot("start")yield*llm.queue(Llm.toolCall({index: 0,id: "call_exec",name: "execute",input: {code: `const r = await fetch(${JSON.stringify(url)}); return { status: r.status, body: await r.text() }`},}),Llm.finish("tool-calls"),)yield*llm.queue(// Control: the direct webfetch tool is blocked by the same config.Llm.toolCall({index: 0,id: "call_wf",name: "webfetch",input: {url: url+"?direct"}}),Llm.finish("tool-calls"),)yield*llm.queue(Llm.text("Done: fetch went through despite webfetch deny."))yield*ui.submit("Fetch the probe URL")yield*ui.waitFor("Done: fetch went through",{timeout: 60_000})yield*Effect.sleep(1500)yield*ui.screenshot("after")yield*Effect.log(`local server received ${hits.length} request(s): ${JSON.stringify(hits)}`)if(hits.filter((h)=>!h.includes("?direct")).length===0)yield*Effect.log("NOT REPRODUCED: no request reached the server")elseyield*Effect.log("REPRODUCED: execute's fetch reached the network although webfetch is denied")constdirect=hits.filter((h)=>h.includes("?direct")).lengthyield*Effect.log(`direct webfetch requests: ${direct} (expected 0, tool is denied)`)server.stop(true)}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Reproduced on dev: a Code Mode fetch reaches the network while "webfetch": "deny" is set, and no approval request is created. The check belongs inside the fetch global, immediately before the request is dispatched, next to the file:// guard from #54510 — a Code Mode extension's extension.before hook runs after the global's body, so gating there would deny only the result, not the request itself.
Activity
opencode-agent commentedon Oct 11, 2026
Thanks for the report. I could reproduce this on 2.0.26 (the latest release, since no version was given), and it still happens on the latest
dev(38454c6).What I did:
"permission": { "webfetch": "deny" }in the config.executetool withawait fetch("http://127.0.0.1:<port>/probe")against a local server that logs requests.webfetchdirectly on the same server.The
fetchinsideexecutereached the server with no permission prompt or error, while the directwebfetchcall was blocked as expected. The recording and screenshot below show it, and the script below reproduces it.Related: #50771 (with open PR #54510) covers
file://URLs in the same Code Modefetchgetting past thereadpermission. That fix doesn't cover HTTP requests, so this is a separate issue.recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.argszero commentedon Oct 12, 2026
I'd like to work on this.
Reproduced on
dev: a Code Modefetchreaches the network while"webfetch": "deny"is set, and no approval request is created. The check belongs inside thefetchglobal, immediately before the request is dispatched, next to thefile://guard from #54510 — a Code Mode extension'sextension.beforehook runs after the global's body, so gating there would deny only the result, not the request itself.rekram1-node commentedon Nov 5, 2026
Fixed by #59954: Code Mode fetch now goes through the webfetch permission rules.