Skip to content

fix(agent): stop network tools being granted a standing approval - #6

Merged
voidstackloop merged 1 commit into
voidstackloop:mainfrom
ConsultingFuture4200:fix/no-auto-approve-network-tools
Jul 25, 2026
Merged

fix(agent): stop network tools being granted a standing approval#6
voidstackloop merged 1 commit into
voidstackloop:mainfrom
ConsultingFuture4200:fix/no-auto-approve-network-tools

Conversation

@ConsultingFuture4200

Copy link
Copy Markdown
Contributor

Problem

READ_ONLY_TOOLS in Chat.tsx gates the "Always allow this session" button. Once a tool is in that set and the user grants it, every later call resolves itself with no confirmation card for the rest of the session.

The set is named for the wrong predicate. It contains six tools that don't modify the workspace but are not side-effect free:

  • capture_page_screenshot — loads a model-chosen URL in a real BrowserWindow and writes a PNG into the workspace. Not read-only in either sense.
  • fetch_url, web_search, github_read_file, github_list_repositories, github_repository_tree — each sends a request to a destination the model chooses. The GitHub ones authenticate with the user's linked token.

Agent mode's inputs are not trusted: it reads file contents and web pages, and instructions embedded in that content can steer subsequent tool calls. A standing grant on fetch_url — the most natural click in the product during any research task — is therefore an unattended outbound channel for whatever the model has already read, firing on every turn with nothing shown to the user. networkToolsEnabled defaults to true, so nothing else stands in the way.

This needs no shell injection or other bug to reach; the classification alone is enough.

Fix

The classification moves to lib/tool-approval.ts and is drawn on "the user has nothing to lose by never being asked again" rather than "doesn't write to the workspace". Workspace-local reads keep the standing grant; the six above keep their per-call prompt.

It lists what qualifies rather than what doesn't, so it stays default-deny — a tool added to AGENT_TOOLS later needs per-call approval until someone classifies it deliberately. That property already held via the old set and is worth keeping.

It is a separate module mainly so it can be unit-tested; Chat.tsx has no component tests, and this is a rule worth pinning down. It follows the existing frontend/src/lib/*.ts + co-located *.test.ts convention.

Nothing is disabled. All six tools work exactly as before — they just don't get a standing approval.

What this doesn't fix

I'd rather flag this than let the PR imply more than it delivers: approval is enforced in the renderer, not behind the IPC boundary. ipcMain.handle("tools:execute") has no notion of approval, and runVerification in Chat.tsx already calls run_command outside the approval flow. So this narrows one specific unattended channel; it does not make the approval boundary sound. Happy to open a separate issue for that if it's useful.

Trade-off

This is the one change in the batch that touches product behaviour rather than fixing a clear defect, so it's your call. The cost is real: web_search and fetch_url are the most repeatedly-called tools in a research loop, and this makes each one a click. If you'd rather keep the convenience, a reasonable alternative is a separate opt-in setting for network-tool auto-approval, so the default is safe but the workflow is recoverable. I'm happy to rework it that way, or to drop it to capture_page_screenshot only — that one writes to the workspace from a set named READ_ONLY_TOOLS, which looks like a plain misclassification regardless of where you land on the network question.

Tests

lib/tool-approval.test.ts — workspace-local reads qualify; each network tool does not; capture_page_screenshot does not; effectful tools do not; an unknown tool name defaults to denied.

npm run lint, npx tsc -b, npm test (73 passed) and npm run build all clean.

Ordering

Worth landing #2 first. git_diff stays auto-approvable here, and that's only defensible once its path argument can't reach the shell.

READ_ONLY_TOOLS gated the "always allow this session" button. It included
capture_page_screenshot, which fetches a model-chosen URL and writes a PNG
into the workspace — not read-only in either sense — along with
web_search, fetch_url and the three github_* tools.

Those five are read-only with respect to the workspace, but each sends a
request to a destination the model chooses. Agent mode reads file contents
and web pages, and instructions embedded in that content can steer later
tool calls, so a standing grant on fetch_url becomes an outbound channel
for whatever the model has already read — firing every turn with no prompt
shown.

The classification moves to lib/tool-approval.ts so it can be unit-tested
(Chat.tsx has no component tests) and lists only what qualifies, keeping it
default-deny for tools added later. Network tools still work exactly as
before; they just keep their per-call prompt.
@voidstackloop
voidstackloop merged commit 2d5861a into voidstackloop:main Jul 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants