MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Tool Definition & Lifecycle

Destructive Tool Without Confirmation

MEDIUMCWE: CWE-862Rule: MCP-201

An MCP tool that performs irreversible operations such as file deletion, database mutation, or HTTP DELETE executes without requiring explicit user approval, allowing a single LLM decision to cause unrecoverable data loss.

What it is

Missing authorization check (CWE-862) on destructive operations — specifically, the absence of any confirmation gate before invoking sinks such as fs.unlinkSync, os.remove, shutil.rmtree, DROP TABLE, DELETE FROM, or HTTP DELETE/PUT/PATCH. The tool accepts input and immediately executes the destructive action with no dry-run path, idempotency key, or elicit() round-trip to obtain explicit human approval.

Why it matters for MCP

MCP tools are invoked autonomously by LLMs that may chain multiple tool calls within a single reasoning step, meaning a misinterpreted instruction or prompt-injected directive can trigger deletion before any human reviews the action. Unlike traditional web APIs where a human explicitly clicks a confirm button, MCP collapses the confirmation UX into the LLM's own judgment, removing the human from the loop by default. Tool composition amplifies this risk: a file-listing tool followed by a file-removal tool can be orchestrated end-to-end by the model with no natural pause for user intervention.

Vulnerable example

example.js
1
import * as fs from "fs";
2
3
server.tool(
4
  "remove_workspace_file",
5
  "Remove a file from the workspace.",
6
  async ({ path }: { path: string }) => {
7
    fs.unlinkSync(path);
8
    return { ok: true };
9
  },
10
);

Secure example

example.js
1
import * as fs from "fs";
2
3
server.tool(
4
  "remove_workspace_file",
5
  "Remove a file from the workspace.",
6
  async ({ path }: { path: string }, { elicit }) => {
7
    const ack = await elicit({ prompt: `Permanently delete ${path}? This cannot be undone.` });
8
    if (!ack.confirmed) return { ok: false, reason: "User cancelled." };
9
    fs.unlinkSync(path);
10
    return { ok: true };
11
  },
12
);

How MCPSafe detects this

MCPSafe performs a file-scoped conjunction check: it confirms both the presence of a tool registration call (server.tool / @mcp.tool) and at least one destructive sink (fs.unlink, os.remove, shutil.rmtree, DROP\s+TABLE, DELETE\s+FROM, TRUNCATE, UPDATE\s+\S+\s+SET, HTTP DELETE/PUT/PATCH methods, subprocess.run, exec, or spawn), then flags the file only when none of the confirmation patterns — elicit(), dry_run parameter, dryRun flag, or idempotency_key — appear anywhere in the same file.

See the full threat catalog for every documented detection.

Further reading

  • CWE-862: Missing Authorization
  • MCP Specification: Elicitation
  • OWASP: Insecure Direct Object Reference (Authorization Failures)
  • OWASP LLM Top 10: LLM06 - Excessive Agency

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now