IntentiAI

Request fields passed to a paid call without validation

Request fields reaching a paid call with no validation.

Rule unvalidated-input-to-paid-callCost audit

Why it costs money

An endpoint built to write a product blurb from a name and a tone will, if it passes request fields straight through, run whatever the caller sends: any prompt, any length, any image. At that point it is a free proxy to a paid model, and the workload is set by whoever uses it, not by your product.

Size matters too. A field meant to hold a product name can carry a 100,000-token document, and it is billed as input on every request.

Example

Flagged

import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic();

export async function POST(req: Request) {
  const { productName, tone, prompt } = await req.json();
  const res = await anthropic.messages.create({
    model: "claude-sonnet-4-5",
    max_tokens: 400,
    messages: [
      { role: "user", content: prompt ?? "Write a " + tone + " product blurb for " + productName },
    ],
  });
  return Response.json(res.content);
}

Fixed

import Anthropic from "@anthropic-ai/sdk";
import { z } from "zod";

const anthropic = new Anthropic();
const Body = z.object({
  productName: z.string().min(1).max(80),
  tone: z.enum(["friendly", "formal", "playful"]),
});

export async function POST(req: Request) {
  const parsed = Body.safeParse(await req.json());
  if (!parsed.success) return new Response("Invalid request", { status: 400 });
  const { productName, tone } = parsed.data;
  const res = await anthropic.messages.create({
    model: "claude-sonnet-4-5",
    max_tokens: 400,
    messages: [{ role: "user", content: "Write a " + tone + " product blurb for " + productName }],
  });
  return Response.json(res.content);
}

How to fix it

Parse the body with a schema before the paid call. Restrict choice fields to an allowed set, put a maximum length on free text, and build the prompt on the server from those values instead of accepting a prompt from the client.

Reject invalid requests early, before they use up rate-limit quota or reach the model.

What the audit detects

  • Files where an LLM call sits in a request handler and the handler reads the request body (req.json(), req.body, request.formData()).
  • Silent if the file contains any validation signal: zod, safeParse, a schema library such as pydantic, yup, joi or ajv, an enum or Literal type, an allowlist, .includes(), assert or a validate function.
  • Silent if the file checks identity (an authorization header, a session user, getServerSession, requireAuth, login_required, current_user and similar), since abuse then costs an account. Rate limiting alone does not silence it. Validation in shared middleware in another file is not visible to it.

Research

OWASP Top 10 for LLM Applications 2025: LLM10 Unbounded Consumption. Unrestricted user input to a model endpoint allows resource-consumption abuse, where attackers drive paid inference with inputs the application was never meant to serve.

Request fields passed to a paid call without validation: LLM cost rule | IntentiAI