T09 · Insecure Skill Coding Practices
- Location
src/tools/gmail-extra.ts:3069- Finding
Destructive Gmail deletion tools bypass user-bound confirmation
- Content
View full analysis
Vulnerability Details
File Location:
src/tools/gmail-extra.ts:3069-3078,src/tools/gmail-extra.ts:3581-3591,src/tools/gmail-extra.ts:4132-4141, andsrc/tools/gmail-extra.ts:4230-4239
Vulnerability Type: Missing user-bound confirmation for destructive operations
Risk Level: MediumThe corresponding behavior is also included in the executable bundle at
dist/index.js.Vulnerable Code
Draft deletion accepts a model-supplied
forceBoolean and then delegates directly to the destructive command:ts server.registerTool('gog_gmail_drafts_delete', { description: 'Permanently delete a Gmail draft (not reversible — drafts do not go to Trash). Requires force:true to delete non-interactively.', annotations: { destructiveHint: true, openWorldHint: true }, inputSchema: z.object({ draftId: z.string().describe('Draft ID'), force: z.boolean().optional().describe('Required to delete in this non-interactive context — without it the delete is refused as a safety guard.'), account: accountParam, }), }, async ({ draftId, account, force }) => { const args: GogArg[] = ['gmail', 'drafts', 'delete', pos(draftId)]; if (force) args.push('--force'); return runOrDiagnose(args, { account }); });Label, filter, and send-as deletion append
--forceautomatically without invoking the project’s host-mediated confirmation mechanism:ts return runOrDiagnose( ['gmail', 'labels', 'delete', pos(labelIdOrName), '--force'], { account }, );ts return runOrDiagnose( ['gmail', 'settings', 'filters', 'delete', pos(filterId), '--force'], { account }, );ts return runOrDiagnose( ['gmail', 'settings', 'sendas', 'delete', pos(email), '--force'], { account }, );Technical Analysis
The project already implements user-bound confirmation controls for sensitive actions such as permanent batch deletion, sending mail, enabling vacation responses, creating forwarding filters, and creating sen ...[truncated 2418 chars]
- Remediation
View remediation
Remediation Suggestions
- Apply
requireDispatchConfirmationto every destructive deletion tool before constructing or executing a forced command. - Display an exact-target preview containing the draft, label, filter, or send-as identity that will be deleted.
- Bind fallback confirmation tokens to the account, tool name, target identifier, and current target state so approval cannot be replayed for a different object.
- Refuse the operation when the MCP host cannot provide confirmation, rather than treating a model-supplied
forcevalue as user consent. - Append
--forceonly after successful user confirmation. - Re-fetch the target before execution where practical and reject the operation if its identity or relevant state changed after confirmation.
- Add regression tests proving that:
- The first invocation cannot delete anything.
- Unsupported confirmation returns an error without calling
gog. - Rejected confirmation performs no deletion.
- A token for one target cannot authorize another target.
--forceappears only on the post-confirmation execution path.
- Apply
