BUZZ AI Gateway
HomeBlog › When Billing Overflows

When Billing Overflows: How One Integer Can Turn Charges Into Credits

There is a bug pattern that keeps surfacing across LLM gateways, reseller platforms, and homegrown metering layers. It is not a jailbreak and not a prompt injection. It is much older and much more boring: an integer overflow in the billing path, triggered by a parameter the user fully controls. When it fires, the platform does not overcharge the user — it pays them. This is a field note on why it happens, how to recognize it, and how to shut it down.

Published 2026-07-08 · Industry note · Reading time ~7 min

The shape of the bug

Usage-based billing for AI APIs almost always ends in the same arithmetic: multiply a quantity by a rate, round, and store the result as a signed integer — commonly an int64 representing a fractional currency unit or an internal “quota” point. The quantity is usually a token count. But several request parameters that feed that quantity are supplied by the caller:

Take any of these, make it absurdly large, and the intermediate product grows without bound. A signed 64-bit integer tops out at 9,223,372,036,854,775,807 — about 9.22 × 1018. Push past that and the value does not clamp or error; it wraps around to a negative number. In C, Go, Java, Rust release builds, and plenty of other environments, signed overflow either wraps silently or is explicitly defined to wrap. The moment your computed charge goes negative, the settlement step that was supposed to subtract from the user’s balance adds to it. A charge became a credit.

The attacker never needs to break your auth, your model, or your network. They just send a number your arithmetic cannot hold.

A concrete walk-through

Suppose an image endpoint prices each image at a small per-image quota, and the number of images n is applied as a multiplier. Simplified, the settlement looks like this:

// quota is an int64 of internal billing points
quota := perImageQuota * int64(n)          // n comes straight from the request
user.Balance -= quota                       // "charge" the user

With n = 3 this is a normal charge. With n in the billions or larger, perImageQuota * n sails past the int64 ceiling and wraps negative. Now user.Balance -= (negative) increases the balance. The same story plays out when the multiplier is a floating-point value first — a huge float64 converted back to int64 is undefined-or-wrapping in most languages, and lands negative just as easily.

Decimal libraries do not save you by themselves. A big-decimal type will happily hold a number far larger than int64 — the overflow moves to the moment you call something like .IntPart() or cast the decimal back to a native integer for storage. If that final narrowing step has no bounds check, the wrap happens there instead.

Why it slips through review

Three reasons this bug is so common in AI billing specifically:

  1. The multipliers are new. Text billing was token-in, token-out — both server-measured. Image n, video seconds, and aggressive pre-charge estimators introduced caller-controlled multipliers into a code path that historically only handled server-measured quantities. The validation never caught up.
  2. Nobody tests the absurd input. Test suites cover n = 1, n = 4, maybe n = 10. They do not cover n = 9999999999, because no legitimate user sends that. The overflow lives in a region of the input space that only an attacker visits.
  3. The failure is invisible in the happy path. Overflow produces no exception, no 500, no log line. Balances silently drift up instead of down. Unless you are alerting on negative computed charges, the first signal is an accounting discrepancy weeks later.

How to know if you are exposed

You can answer this in an afternoon:

How to defend

The durable fix is two independent layers. Either one alone helps; together they close the class of bug, not just the one instance you found.

1. Clamp at every quota exit (defense in depth)

Wherever a computed charge is narrowed to the integer you store, pass it through a single clamp that (a) compares in a type that cannot overflow — a big-decimal or a saturating check — before the narrowing, and (b) bounds the result to [0, MAX_SAFE]. A charge is never negative; a single request is never astronomically large. Pick a ceiling comfortably below int64 max (say 1015 billing points) so later additions cannot re-overflow, and pin the floor at zero so no arithmetic path can ever credit a user through the charge route.

// One helper, used at every settlement/pre-charge exit.
func clampQuota(d Decimal) int64 {
    if d.LessThanOrEqual(Zero) { return 0 }        // never credit via a charge
    if d.GreaterThan(MaxSafe)  { return MaxSafe }  // compare before narrowing
    return d.RoundToInt64()
}

The key detail: the comparison must happen in the wide type, before you cast down. Clamping after the cast is too late — the wrap has already happened.

2. Validate the inputs at the boundary

Reject the absurd parameter before it ever reaches arithmetic. Cap n, seconds, and max_tokens at sane maxima and return a 400 when a request exceeds them. Make the limits configurable so operations can tune them without a deploy. This layer also spares you the second, quieter problem: a merely large-but-not-overflowing parameter that produces a real, gigantic, legitimate charge you then have to refund and apologize for.

LayerCatchesMiss mode if absent
Input validation (400 on absurd param)The attack before arithmetic; also legitimate-but-huge requestsOverflow reaches the math; or a real astronomical charge
Quota clamp at every exitOverflow anywhere in the pipeline, including paths you forgotA new code path re-introduces the wrap

The wider lesson

This is a reminder that AI billing is a security surface, not just an accounting detail. The interesting attacks on inference platforms are not always exotic. Sometimes the exploit is a forty-year-old integer overflow wearing a new hat, reachable because a caller-controlled multiplier was added to a billing path that used to only see server-measured numbers. Treat every request parameter that touches a charge as hostile input, bound it at the boundary, and clamp it again at the exit. Two cheap checks turn a “charges became credits” incident into a rejected request and a log line.

Q1: Is this a jailbreak or prompt-injection issue?

No. It is a classic integer overflow in the billing arithmetic, triggered by an oversized but perfectly ordinary API parameter. It has nothing to do with the model’s behavior.

Q2: Doesn’t using a big-decimal library prevent it?

Only partly. A big-decimal can hold the oversized intermediate, but the overflow reappears the moment you narrow it back to a native int64 for storage — unless that narrowing step has a bounds check. Clamp before you cast down.

Q3: How do I check whether I have already been hit?

Query your billing ledger for any charge that settled at or below zero on a paid model, and look for user balances that rose without a corresponding payment. A negative computed charge is the signature.

Billing you can trust

BUZZ AI Gateway is pure pay-per-token with bounded, validated billing across text, image, and video endpoints. One key, transparent pricing, no surprises in either direction.

Create an account
Published: 2026-07-08
Last reviewed: 2026-07-08