Missing Human Confirmation for Destructive Operations
What this checks: This check flags a destructive action, like deleting something, that runs automatically with no one asked to confirm it first. It matters because irreversible actions should pause for a person to say yes, so a bad or tricked instruction can't quietly wipe out data.
Source code auto-executes delete operation with auto_approve=True and no confirmation
How this rule decides. Each strategy below is a deterministic analysis the detector runs against the MCP server's static metadata, source code, and (when present) live connection handshake.
composite- 1
Tool Handler Region Gate
tool-handler-region-gate - 2
Handler Reachability Closure
handler-reachability-closure - 3
Case Clause Tool Attribution
case-clause-tool-attribution - 4
Schema Surface Duplicate Suppression
schema-surface-duplicate-suppression - 5
Ecmascript Only Source Surface
ecmascript-only-source-surface - 6
Morpheme Tokenisation
morpheme-tokenisation - 7
Required Param Check
required-param-check - 8
Annotation Partial Mitigation
annotation-partial-mitigation - 9
Structural Test File Detection
structural-test-file-detection - 10
Ancestor Guard Walk
ancestor-guard-walk - 11
Preceding Sibling Confirmation
preceding-sibling-confirmation - 12
Receiver Method Guard
receiver-method-guard
What we found. Each finding below carries a structured proof chain from source (where untrusted data enters) through propagation (how it flows) to a sink (where the dangerous operation occurs), including any mitigations checked for and the potential impact if exploited. Every link is independently verifiable against the cited location.
Proof chain
6 steps from untrusted source to potential impact. Each step is independently verifiable against the cited location.
SourceUser Parameter - Where
dist/index.js:369:1- Observed
server.registerTool("delete_relations", {- Why untrusted
- McpServer.registerTool(name, config, handler) registers the MCP tool "delete_relations" at dist/index.js:369. Everything the handler reaches is invokable by the model with parameters the model chooses, which is what makes an unguarded destructive operation below it an oversight gap rather than ordinary application code.
PropagationFunction Call - At
dist/index.js:386:11- Observed
Reachable from the registered handler: "deleteRelations" is called inside the handler body or inside a callable declared in the same file that the handler calls. await knowledgeGraphManager.deleteRelations(relations);
SinkPrivilege Grant - Where
dist/index.js:386:11- Observed
deleteRelations(...) — destructive operation on normal control-flow path with no confirmation guard.
MitigationConfirmation GateAbsent - Where
dist/index.js:386:11- Detail
- No confirmation pattern (guard-call, guard-condition identifier, receiver.method) anywhere on the ancestor chain from the call site to the enclosing function boundary.
ImpactPrivilege Escalation - Scope
- user-data
- Exploitability
- Moderate
- Scenario
- Unguarded destructive call "deleteRelations", reachable from the MCP tool "delete_relations". Single-item operation — still requires confirmation under Art.14. PREMISE (a property of the DEPLOYMENT, not of this artifact): the client auto-approves, or has a standing approval for this tool. GIVEN that premise: an AI agent executing this handler under prompt injection can invoke the destructive path without any client-side consent moment; the operation completes and writes its side effects before the user sees the assistant's response.
MitigationAnnotation HintPresent - Where
dist/index.js:369:1- Detail
- annotations.destructiveHint === true is declared at the tool registration (McpServer.registerTool(name, config, handler)). destructiveHint declared — partial mitigation: the annotation advertises the risk but does not enforce a confirmation. MCP-aware clients (Claude Desktop, Cursor) will prompt; MCP-unaware or auto-approving clients ignore it, so the handler still reaches the destructive call with no human in the loop. The residual gap is an enforced in-handler or server-side confirmation.
- +0.1confirmation-gate absentNo confirmation-gate found — No confirmation pattern (guard-call, guard-condition identifier, receiver.method) anywhere on the ancestor chain from the call site to the enclosing function boundary.
- +0.08destructive_verb_destructiveCall symbol contains a destructive verb — recorded in the chain because the auditor needs to see WHY the symbol was flagged.
- +0.1no_guard_in_ancestor_chainAncestor walk from the call to the enclosing function body found no confirmation pattern. The static engine cannot prove the absence of a server-middleware confirmation; the charter caps confidence at 0.92 for that reason.
- +0.08reachable_from_registered_tool_handlerThe call lies inside the handler registered by McpServer.registerTool(name, config, handler) at dist/index.js:369 for tool "delete_relations", or inside a same-file callable that handler calls. This is the factor that distinguishes a K4 subject from ordinary application code: without it the rule was convicting DOM helpers, keepalive timers and Express route registrations.
- -0.3annotation-hint presentMitigation "annotation-hint" found at dist/index.js:369:1: annotations.destructiveHint === true is declared at the tool registration (McpServer.registerTool(name, config, handler)). destructiveHint declared — partial mitigation: the annotation advertises the risk but does not enforce a confirmation. MCP-aware clients (Claude Desktop, Cursor) will prompt; MCP-unaware or auto-approving clients ignore it, so the handler still reaches the destructive call with no human in the loop. The residual gap is an enforced in-handler or server-side confirmation.
ISO-42001-A.9.2ISO/IEC 42001:2023 Annex A Control 9.2 — Human oversight
A.9.2 requires human oversight mechanisms including the ability to halt, intervene, or override. Unguarded destructive code paths defeat the control by design.
- 1
inspect-sourceOpen this line and confirm it registers an MCP tool handler for the tool "delete_relations" (McpServer.registerTool(name, config, handler)). Then confirm the destructive call at dist/index.js:386 is inside that handler's body, or inside a function declared in the same file that the handler calls. If neither holds, the finding does not stand: an operation a model cannot invoke is not an Art. 14 oversight gap.
Target:
dist/index.js:369:1Expect: A tool registration whose handler reaches the destructive call.
- 2
inspect-sourceOpen the file at this line. Confirm the call symbol "deleteRelations" is a destructive operation (verb: "delete", class: destructive), and that the enclosing function body contains no confirmation call (confirm/prompt/approve/ask/verify/acknowledge/requireConfirmation/requestApproval/elicit) and no IfStatement whose condition references a force/confirm/approved flag.
Target:
dist/index.js:386:11Expect: A destructive call with no confirmation guard in any enclosing scope.
Proof chain
6 steps from untrusted source to potential impact. Each step is independently verifiable against the cited location.
SourceUser Parameter - Where
dist/index.js:316:1- Observed
server.registerTool("delete_entities", {- Why untrusted
- McpServer.registerTool(name, config, handler) registers the MCP tool "delete_entities" at dist/index.js:316. Everything the handler reaches is invokable by the model with parameters the model chooses, which is what makes an unguarded destructive operation below it an oversight gap rather than ordinary application code.
PropagationFunction Call - At
dist/index.js:333:11- Observed
Reachable from the registered handler: "deleteEntities" is called inside the handler body or inside a callable declared in the same file that the handler calls. await knowledgeGraphManager.deleteEntities(entityNames);
SinkPrivilege Grant - Where
dist/index.js:333:11- Observed
deleteEntities(...) — destructive operation on normal control-flow path with no confirmation guard.
MitigationConfirmation GateAbsent - Where
dist/index.js:333:11- Detail
- No confirmation pattern (guard-call, guard-condition identifier, receiver.method) anywhere on the ancestor chain from the call site to the enclosing function boundary.
ImpactPrivilege Escalation - Scope
- user-data
- Exploitability
- Moderate
- Scenario
- Unguarded destructive call "deleteEntities", reachable from the MCP tool "delete_entities". Single-item operation — still requires confirmation under Art.14. PREMISE (a property of the DEPLOYMENT, not of this artifact): the client auto-approves, or has a standing approval for this tool. GIVEN that premise: an AI agent executing this handler under prompt injection can invoke the destructive path without any client-side consent moment; the operation completes and writes its side effects before the user sees the assistant's response.
MitigationAnnotation HintPresent - Where
dist/index.js:316:1- Detail
- annotations.destructiveHint === true is declared at the tool registration (McpServer.registerTool(name, config, handler)). destructiveHint declared — partial mitigation: the annotation advertises the risk but does not enforce a confirmation. MCP-aware clients (Claude Desktop, Cursor) will prompt; MCP-unaware or auto-approving clients ignore it, so the handler still reaches the destructive call with no human in the loop. The residual gap is an enforced in-handler or server-side confirmation.
- +0.1confirmation-gate absentNo confirmation-gate found — No confirmation pattern (guard-call, guard-condition identifier, receiver.method) anywhere on the ancestor chain from the call site to the enclosing function boundary.
- +0.08destructive_verb_destructiveCall symbol contains a destructive verb — recorded in the chain because the auditor needs to see WHY the symbol was flagged.
- +0.1no_guard_in_ancestor_chainAncestor walk from the call to the enclosing function body found no confirmation pattern. The static engine cannot prove the absence of a server-middleware confirmation; the charter caps confidence at 0.92 for that reason.
- +0.08reachable_from_registered_tool_handlerThe call lies inside the handler registered by McpServer.registerTool(name, config, handler) at dist/index.js:316 for tool "delete_entities", or inside a same-file callable that handler calls. This is the factor that distinguishes a K4 subject from ordinary application code: without it the rule was convicting DOM helpers, keepalive timers and Express route registrations.
- -0.3annotation-hint presentMitigation "annotation-hint" found at dist/index.js:316:1: annotations.destructiveHint === true is declared at the tool registration (McpServer.registerTool(name, config, handler)). destructiveHint declared — partial mitigation: the annotation advertises the risk but does not enforce a confirmation. MCP-aware clients (Claude Desktop, Cursor) will prompt; MCP-unaware or auto-approving clients ignore it, so the handler still reaches the destructive call with no human in the loop. The residual gap is an enforced in-handler or server-side confirmation.
ISO-42001-A.9.2ISO/IEC 42001:2023 Annex A Control 9.2 — Human oversight
A.9.2 requires human oversight mechanisms including the ability to halt, intervene, or override. Unguarded destructive code paths defeat the control by design.
- 1
inspect-sourceOpen this line and confirm it registers an MCP tool handler for the tool "delete_entities" (McpServer.registerTool(name, config, handler)). Then confirm the destructive call at dist/index.js:333 is inside that handler's body, or inside a function declared in the same file that the handler calls. If neither holds, the finding does not stand: an operation a model cannot invoke is not an Art. 14 oversight gap.
Target:
dist/index.js:316:1Expect: A tool registration whose handler reaches the destructive call.
- 2
inspect-sourceOpen the file at this line. Confirm the call symbol "deleteEntities" is a destructive operation (verb: "delete", class: destructive), and that the enclosing function body contains no confirmation call (confirm/prompt/approve/ask/verify/acknowledge/requireConfirmation/requestApproval/elicit) and no IfStatement whose condition references a force/confirm/approved flag.
Target:
dist/index.js:333:11Expect: A destructive call with no confirmation guard in any enclosing scope.
Proof chain
6 steps from untrusted source to potential impact. Each step is independently verifiable against the cited location.
SourceUser Parameter - Where
dist/index.js:341:1- Observed
server.registerTool("delete_observations", {- Why untrusted
- McpServer.registerTool(name, config, handler) registers the MCP tool "delete_observations" at dist/index.js:341. Everything the handler reaches is invokable by the model with parameters the model chooses, which is what makes an unguarded destructive operation below it an oversight gap rather than ordinary application code.
PropagationFunction Call - At
dist/index.js:361:11- Observed
Reachable from the registered handler: "deleteObservations" is called inside the handler body or inside a callable declared in the same file that the handler calls. await knowledgeGraphManager.deleteObservations(deletions);
SinkPrivilege Grant - Where
dist/index.js:361:11- Observed
deleteObservations(...) — destructive operation on normal control-flow path with no confirmation guard.
MitigationConfirmation GateAbsent - Where
dist/index.js:361:11- Detail
- No confirmation pattern (guard-call, guard-condition identifier, receiver.method) anywhere on the ancestor chain from the call site to the enclosing function boundary.
ImpactPrivilege Escalation - Scope
- user-data
- Exploitability
- Moderate
- Scenario
- Unguarded destructive call "deleteObservations", reachable from the MCP tool "delete_observations". Single-item operation — still requires confirmation under Art.14. PREMISE (a property of the DEPLOYMENT, not of this artifact): the client auto-approves, or has a standing approval for this tool. GIVEN that premise: an AI agent executing this handler under prompt injection can invoke the destructive path without any client-side consent moment; the operation completes and writes its side effects before the user sees the assistant's response.
MitigationAnnotation HintPresent - Where
dist/index.js:341:1- Detail
- annotations.destructiveHint === true is declared at the tool registration (McpServer.registerTool(name, config, handler)). destructiveHint declared — partial mitigation: the annotation advertises the risk but does not enforce a confirmation. MCP-aware clients (Claude Desktop, Cursor) will prompt; MCP-unaware or auto-approving clients ignore it, so the handler still reaches the destructive call with no human in the loop. The residual gap is an enforced in-handler or server-side confirmation.
- +0.1confirmation-gate absentNo confirmation-gate found — No confirmation pattern (guard-call, guard-condition identifier, receiver.method) anywhere on the ancestor chain from the call site to the enclosing function boundary.
- +0.08destructive_verb_destructiveCall symbol contains a destructive verb — recorded in the chain because the auditor needs to see WHY the symbol was flagged.
- +0.1no_guard_in_ancestor_chainAncestor walk from the call to the enclosing function body found no confirmation pattern. The static engine cannot prove the absence of a server-middleware confirmation; the charter caps confidence at 0.92 for that reason.
- +0.08reachable_from_registered_tool_handlerThe call lies inside the handler registered by McpServer.registerTool(name, config, handler) at dist/index.js:341 for tool "delete_observations", or inside a same-file callable that handler calls. This is the factor that distinguishes a K4 subject from ordinary application code: without it the rule was convicting DOM helpers, keepalive timers and Express route registrations.
- -0.3annotation-hint presentMitigation "annotation-hint" found at dist/index.js:341:1: annotations.destructiveHint === true is declared at the tool registration (McpServer.registerTool(name, config, handler)). destructiveHint declared — partial mitigation: the annotation advertises the risk but does not enforce a confirmation. MCP-aware clients (Claude Desktop, Cursor) will prompt; MCP-unaware or auto-approving clients ignore it, so the handler still reaches the destructive call with no human in the loop. The residual gap is an enforced in-handler or server-side confirmation.
ISO-42001-A.9.2ISO/IEC 42001:2023 Annex A Control 9.2 — Human oversight
A.9.2 requires human oversight mechanisms including the ability to halt, intervene, or override. Unguarded destructive code paths defeat the control by design.
- 1
inspect-sourceOpen this line and confirm it registers an MCP tool handler for the tool "delete_observations" (McpServer.registerTool(name, config, handler)). Then confirm the destructive call at dist/index.js:361 is inside that handler's body, or inside a function declared in the same file that the handler calls. If neither holds, the finding does not stand: an operation a model cannot invoke is not an Art. 14 oversight gap.
Target:
dist/index.js:341:1Expect: A tool registration whose handler reaches the destructive call.
- 2
inspect-sourceOpen the file at this line. Confirm the call symbol "deleteObservations" is a destructive operation (verb: "delete", class: destructive), and that the enclosing function body contains no confirmation call (confirm/prompt/approve/ask/verify/acknowledge/requireConfirmation/requestApproval/elicit) and no IfStatement whose condition references a force/confirm/approved flag.
Target:
dist/index.js:361:11Expect: A destructive call with no confirmation guard in any enclosing scope.