Skip to content

confirm_cost is not a human confirmation and its token is precomputable (paid-resource cost safeguard bypass) #318

Description

@chrisbartoloburlo

Summary

The cost-confirmation safeguard for creating paid resources doesn't provide the guarantee its tool schemas state. confirm_cost performs no human interaction, and the confirm_cost_id it returns is a deterministic hash of a public, low-entropy cost object — so an autonomous or prompt-injected agent can satisfy the gate (or precompute the token and skip confirm_cost entirely) and create billable resources with no human ever confirming costs.

Responsible-disclosure note: I've omitted the literal token values below. They're trivially derivable from the open-source code — I'm just not pasting a ready-to-use bypass. Happy to share full details privately if you prefer.

Stated guarantee

  • create_project / create_branch input schema: "User must confirm understanding of costs before creating a project/branch."
  • confirm_cost description: "Ask the user to confirm their understanding of the cost … Returns a unique ID … passed to create_project/create_branch."

What the code does

  1. confirm_cost is execute: async (cost) => ({ confirmation_id: await hashObject(cost) }) (account-tools.ts) — no prompt, no elicitation, no human.
  2. create_branch / create_project accept the call iff hashObject(cost) === confirm_cost_id (branching-tools.ts, account-tools.ts).
  3. getBranchCost() is a constant and project cost is only 0 or 10 (pricing.ts), so the token is a fixed, publicly-derivable value.

So the confirmation is (a) never human-gated and (b) precomputable — an agent can pass a correct confirm_cost_id without ever calling confirm_cost or get_cost.

Impact

An agent holding a valid access token can create billable resources (project $10/mo, branch $0.01344/hr) while bypassing the safeguard meant to ensure a human understood the cost. Given the known prompt-injection surface of MCP tools, injected data could drive unbudgeted resource creation with no cost prompt. This is a safety-guardrail weakness (it requires a valid token), not an auth bypass or data exposure.

Reproduction

A ~15-line script re-implementing hashObject + the pricing.ts constants reproduces the confirmation token with no account and no billed calls (the create-time check is a pure string comparison against that value). I did not run the paid create call end-to-end.

Suggested fix

Make confirm_cost a real client-side human checkpoint (MCP elicitation), and/or issue an unforgeable, single-use confirmation nonce (bound to org + timestamp, stored and checked once) instead of a deterministic hash of public data.


Found with llmcontract, a session-type runtime monitor for agent/tool protocols. Write-up (redacted PoC): https://github.com/chrisbartoloburlo/llmcontract-mcp-audit/tree/main/servers/supabase

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions