Lessons · LLM06: Unbounded Consumption · warning

The stream keeps running after the user leaves

Close the tab and the model keeps generating, and you keep paying.

Caught by streaming-response-without-abort-handling · CWE-400, CWE-770

What is wrong

Your route streams the model's reply back to the browser, but it never tells the model call when the browser goes away.

When the user closes the tab or navigates away, the connection drops. The model call does not know, so it keeps generating to the end, and every token is billed.

In development nobody disconnects mid-reply, so this never shows up until the bill does.

How it is used against you

Your chat route uses streamText with a long maximum output.

export async function POST(req: Request) {
  const { prompt } = await req.json();
  return streamText({ model, prompt }).toTextStreamResponse();
}
  1. An attacker writes a short script that sends a request asking for a very long answer.
  2. The script disconnects right after sending, and repeats a few thousand times.
  3. Each request costs the attacker almost nothing. Each one costs you a full-length generation.

The cost: A large provider bill, or hitting your rate limit so real users get errors.

How to spot it

  • streamText, streamObject, or stream: true inside a request handler.
  • No abortSignal or signal passed to that call.
  • No rate limit on the endpoint.

The fix

Paste this into Claude Code, Cursor, or whatever wrote the code. When llm-audit finds the mistake in your project, npx llm-audit prompt gives you the same prompt with every file and line filled in.

Fix this in my project: a streaming model call does not stop when the client disconnects.

Please:
1. Pass the request's abort signal to the model call: abortSignal: req.signal for the AI SDK, or { signal: req.signal } for the OpenAI and Anthropic SDKs.
2. Set a sensible maximum output length for this endpoint.
3. Add rate limiting per user or per IP.

Show me the diff.

Check the rest

A prompt that looks for the same mistake everywhere else, without changing anything yet.

Check this project's streaming AI endpoints for runaway cost, before I ship it.

Look for:
- Streaming model calls (streamText, streamObject, stream: true) that do not receive the request's abort signal.
- Model calls with no maximum output length.
- AI endpoints with no rate limiting or authentication.

For each one, give me the file and line and estimate what one request costs if the client disconnects immediately. Do not change any code yet.

Find it in your code

npx llm-audit scan

Runs on your machine with Semgrep. Nothing is uploaded.