IntentiAI

Public endpoint that spends your model budget

An endpoint anyone can call that spends your model budget.

Rule unauthenticated-llm-endpointCost audit

Why it costs money

If an endpoint calls a model and anyone can reach it, anyone can spend your budget. It only takes one script that finds the URL and calls it in a loop. OWASP calls this denial of wallet: the service stays up, but the bill does not stop.

Nothing in your spend dashboard explains the cause. You see usage rise; the missing login or quota is only visible in the code.

Example

Flagged

from fastapi import FastAPI
from openai import OpenAI
from pydantic import BaseModel

app = FastAPI()
client = OpenAI()


class Question(BaseModel):
    text: str


@app.post("/ask")
def ask(q: Question):
    response = client.chat.completions.create(
        model="gpt-4o",
        max_tokens=500,
        messages=[{"role": "user", "content": q.text}],
    )
    return {"answer": response.choices[0].message.content}

Fixed

from fastapi import Depends, FastAPI, HTTPException
from openai import OpenAI
from pydantic import BaseModel, Field

from app.auth import User, get_current_user  # your auth dependency
from app.quota import daily_quota  # your per-user counter

app = FastAPI()
client = OpenAI()


class Question(BaseModel):
    text: str = Field(max_length=2000)


@app.post("/ask")
def ask(q: Question, user: User = Depends(get_current_user)):
    if not daily_quota.try_consume(user.id):
        raise HTTPException(status_code=429, detail="Daily limit reached")
    response = client.chat.completions.create(
        model="gpt-4o",
        max_tokens=500,
        messages=[{"role": "user", "content": q.text}],
    )
    return {"answer": response.choices[0].message.content}

How to fix it

Require a signed-in user (or an API key you issue) on every route that calls a paid model, and apply a per-user rate limit and a per-user spend cap. Record usage per user so you can see who is spending what.

If the endpoint must stay public, for example a demo, give it a small global budget and a strict per-IP limit, and turn it off automatically when the budget is used up.

What the audit detects

  • LLM calls inside a request handler in a file with no auth or rate-limit signal: auth or authorization checks, jwt, getServerSession, requireAuth, login_required, next-auth, clerk, passport, Depends(...user), rate limit, throttle, limiter or quota.
  • For languages scanned line by line (such as Go, Java or C#), global auth setup anywhere in that language's files counts for every handler.
  • For TypeScript and Python, auth applied by middleware or an API gateway in another file is not visible to it, so confirm before treating an endpoint as exposed. One finding per file.

Research

OWASP Top 10 for LLM Applications 2025: LLM10 Unbounded Consumption. An LLM call on an unauthenticated, unthrottled endpoint lets attackers send high request volumes that create unsustainable pay-per-token cost (denial of wallet).

Public endpoint that spends your model budget: LLM cost rule | IntentiAI