Skip to content

fix(ai-chat)!: always require user approval for destructive operations#1277

Merged
datlechin merged 3 commits into
mainfrom
fix/destructive-tool-confirmation
May 15, 2026
Merged

fix(ai-chat)!: always require user approval for destructive operations#1277
datlechin merged 3 commits into
mainfrom
fix/destructive-tool-confirmation

Conversation

@datlechin
Copy link
Copy Markdown
Member

Security issue

The user reported: AI dropped a table with no confirmation prompt. Reproduction:

  1. Connection in "Silent" safe mode (default)
  2. User sends: "drop jobs table"
  3. AI calls `confirm_destructive_operation` with the magic phrase
  4. Table is dropped immediately — no UI dialog, no approval

The `confirm_destructive_operation` tool's `confirmation_phrase` parameter is security theater — the AI just types it. The real user gate is supposed to be the approval UI, but `computeInitialApprovalState` was auto-approving `.agentOnly` tools whenever the connection used Silent safe mode (and forever once "Always Allow" was clicked).

Fix

`AIChatViewModel+ToolApproval.swift` — `computeInitialApprovalState(for:)` now:

  1. `.readOnly` tools → `.approved` (unchanged)
  2. `.agentOnly` tools (destructive: DROP, TRUNCATE, ALTER...DROP) → always `.pending`, regardless of safe mode level. Read-only connections still get `.denied`. "Always Allow" and Silent mode no longer bypass.
  3. `.write` tools → existing logic (respects safe mode and Always Allow)

`persistAlwaysAllowed(toolName:)` — refuses to record "Always Allow" for `.agentOnly` tools, so the destructive confirmation cannot be permanently skipped.

Tests

5 new tests in `DestructiveToolApprovalTests`:

  • `ConfirmDestructiveOperationChatTool` is in `.agentOnly` mode
  • `.agentOnly.requiresApproval == true`
  • `.readOnly.requiresApproval == false`
  • `.write.requiresApproval == true`
  • `.agentOnly` only allowed in agent chat mode (not ask/edit)

All pass.

Breaking change marker

The `!` in the commit type signals a behavior change: users in Silent safe mode who previously dropped tables without dialogs will now see an approval prompt. This is intentional and the correct behavior.

Test plan

  • Set a connection to Silent safe mode
  • AI Chat: "drop jobs table" → approval prompt appears, table is NOT dropped until user clicks Approve
  • Click Cancel → table is not dropped, error returned to AI
  • Click "Always Allow" → setting is NOT persisted (refresh, next destructive op still prompts)
  • Read-only safe mode → AI gets a denied result without prompting

@datlechin datlechin merged commit 01fda08 into main May 15, 2026
2 checks passed
@datlechin datlechin deleted the fix/destructive-tool-confirmation branch May 15, 2026 09:51
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.

1 participant