Skip to content
TRIAGERS
Deep Dives · 9 min read · TRIAGERS™ Team

Triaging Business Logic Flaw Reports

How to triage business logic bugs: establishing intended behavior before judging deviation, classic flaw classes, quantifying financial impact, and why CVSS underrates them.

A scanner can find reflected XSS because a payload it injected came back unescaped. It cannot find that your checkout accepts a quantity of -1 and credits the customer, because nothing in that request is malformed. Every field is a valid integer, the request matches the API schema, the response is a clean 200, and the money leaves the building. Business logic flaws are the reports where the application does exactly what it was built to do, and what it was built to do is wrong. That makes them the hardest class to triage, because there is no signature to match against and no payload firing to confirm.

Template triage falls apart here for the same reason. You cannot check a logic bug against a known-bad string or a CVE. You have to reconstruct what the feature was supposed to enforce, then decide whether the reporter drove it somewhere it was never meant to go. That reconstruction is most of the job, and it is the part rushed queues skip, which is how genuine six-figure flaws get closed as "working as intended" and how nonsense gets paid because nobody checked the intent.

Establish intended behavior before you judge deviation

You cannot call something a deviation until you know the baseline. A report that says "I applied two coupons and got 40% off" is not a bug on its own. Maybe the program stacks promotions on purpose. The triage question is not "did something unusual happen," it is "did the application violate a rule it actually holds."

The rules are usually written down somewhere, and those documents are your oracles:

  • Pricing pages and plan comparison tables. These state limits the product sells on: seats per tier, API calls per month, "one discount per order." If the reporter bypassed a limit the pricing page advertises, you have a documented rule and a demonstrated break.
  • Terms and conditions and coupon fine print. "Cannot be combined with other offers" is a contract. When the checkout ignores it, the deviation is not a matter of opinion.
  • Help center and onboarding docs. These describe the intended workflow: verify email, then add a payment method, then provision. If the reporter provisioned without paying, the docs establish the step they skipped.
  • The feature's own UI copy. Error messages, disabled buttons, and tooltips encode the rules the front end tries to enforce. A rule the UI blocks but the API does not is a textbook logic flaw.

When none of these pin the rule down, ask the program. A one-line question to the security contact ("is stacking a referral credit on top of a percentage coupon intended?") resolves more logic disputes than any amount of solo reasoning. Do not guess at intent and rate on the guess. Intent is a fact you can usually retrieve, and a verdict built on a retrieved rule survives a dispute where a verdict built on your assumption does not.

The classic classes

Most logic reports fall into a handful of shapes. Knowing the shapes tells you where to look and what to test next.

Negative and overflow quantities. The cart multiplies quantity by unit price. A quantity of -3 produces a negative line total, which nets against the rest of the order or issues a credit. Overflow variants use quantities so large the total wraps a signed integer and goes negative. Test the boundaries: 0, -1, a huge value, and a decimal like 1.9999999 where the app rounds up the goods but truncates the charge.

Currency and rounding abuse. Financial math done in floats, or rounding applied per line item instead of per order, lets an attacker skim fractions of a cent at scale, or convert between currencies at a rate the app computes inconsistently. The single-transaction impact looks like nothing. Multiplied by automation, it is theft. Always ask whether the reporter demonstrated the per-transaction gain and whether it scales.

Coupon and credit stacking. Applying the same coupon twice, combining exclusive offers, or replaying a single-use code by racing two requests before the "used" flag is written. Related: gift card or store credit that is validated at "add to cart" but re-credited on refund, so the attacker buys, refunds to the original card, and keeps the goods.

Workflow state skipping. Multi-step flows (signup, KYC, checkout, provisioning) that trust the client to walk the steps in order. The attacker calls the final step's endpoint directly and skips verification, payment, or approval. The tell is a state machine enforced only by which button the UI shows next.

Refund and chargeback abuse. Refunds that return more than was paid, refunds issued in store credit while the original payment is also reversed, or subscription cancellations that refund a full period after most of it was consumed.

None of these throw an error. That is what unites them, and it is why the reporter's evidence has to carry the weight the application's error handling never will.

Quantify the financial impact honestly

Logic flaws touch money directly, which means the impact is often a number you can actually compute, unlike the "an attacker could potentially" hand-waving that plagues other classes. Make the reporter's claim concrete, or make it concrete yourself:

  • Per-instance gain. What does one execution net the attacker? A free order, $4.10 skimmed, one month of a plan unpaid.
  • Scale and automation. Can it run in a loop? A coupon-stacking bug worth $12 per order that can be scripted against unlimited fresh accounts is a different number from one that needs a manually aged, verified account each time.
  • Attacker cost and friction. Does each execution burn a real payment method, a phone number, a KYC pass? Real friction caps the blast radius and belongs in the write-up.
  • Reversibility. Can the business claw the money back, or is it gone? A fraudulent store credit sitting in the app is recoverable. Goods shipped to a drop address are not.

A good logic report states this arithmetic. When it does not, the triage job is to fill it in before assigning severity, because the number is the severity. "Checkout accepts negative quantities" is a mechanism. "Any unauthenticated user can issue themselves unlimited store credit at $50 per request, scriptable, non-reversible once withdrawn" is a severity, and it is one you can defend.

Why CVSS underrates these, and what to do about it

CVSS was built to describe attacks on the confidentiality, integrity, and availability of information systems. A logic flaw that lets an attacker buy a $2,000 laptop for $20 barely moves the CVSS needle: no confidentiality impact, arguable integrity impact, no availability impact, network vector, low complexity. The vector string might land at a 5-something Medium while the business is bleeding cash. The framework is measuring the wrong axis.

This is the same failure mode we cover in the severity guide: the vulnerability class does not carry the severity, the impact does. For logic bugs, the impact is financial and the honest score comes from the dollar figure and the scale, not from a vector string that has no field for "the company loses money on every transaction." When you write the verdict, lead with the financial impact and treat the CVSS number as a footnote, or the report gets filed at the framework's default and the program underpays a bug that deserved a top bounty. If you are on a platform that forces a CVSS number, document the money next to it so the human making the bounty call sees both.

This cuts the other way too. Logic reports attract severity inflation because "financial impact" sounds critical by default. A rounding bug worth a fraction of a cent per transaction, with no demonstrated path to scale, is not a critical. Make the reporter show the money the same way you would make them show impact on any other class. The number disciplines the rating in both directions.

Reproduction discipline when the bug touches real money

Logic bugs are the class most likely to move actual funds during reproduction, which changes how you verify. You cannot casually re-run a refund exploit twenty times against production billing to be sure. Handle it deliberately:

  • Prefer a staging or sandbox environment with test payment credentials when the program offers one. Ask before you start if the report involves live charges, refunds, or credit issuance.
  • When you must reproduce in production, do it once, cleanly, and document the trail. Record the exact request, the order or transaction ID, the account, and the timestamp, so the program can find and reverse the test transaction in their own logs.
  • Capture the state, not just the response. A logic flaw is proven by the balance, the order total, or the credit sitting in the account afterward, not by a 200. Screenshot the resulting account balance or pull the record from the API, side by side with the request that created it.
  • Verify with two accounts where the flaw crosses users, the same discipline we apply to IDOR reproduction: confirm the money actually moved from or to where the report claims, rather than the attacker simply seeing their own state.

The reporter should give you request and response pairs with the account identifiers and timestamps in them, the same standard as any other class. For logic bugs, add the resulting financial state as the proof. A curl that returns {"discount_applied": true} is a claim. The order confirmation showing a $0.00 total for $2,000 of goods, tied to a named test account and a timestamp, is the bug.

The business logic triage checklist

  1. Retrieve the intended rule from docs, pricing, T&Cs, or by asking the program. Do not rate on assumed intent.
  2. Confirm the report violates a rule the application actually holds, not a behavior that is intended.
  3. Classify the flaw: negative quantity, rounding, stacking, state skip, refund abuse, or a new shape.
  4. Compute the per-instance financial gain, then the scale, automation potential, attacker friction, and reversibility.
  5. Rate on the dollar impact and blast radius, not on the CVSS vector string, and document the money next to any forced number.
  6. Reproduce in sandbox where possible; in production, once, with the transaction trail recorded for reversal.
  7. Prove it with the resulting financial state, not just the response code.

Logic flaws are where careful triage pays for itself: they resist tooling, resist templates, and reward the person who reads the pricing page before rating the bug. TRIAGERS™ fields on-demand triage teams who reconstruct intended behavior and rate on the money, not the vocabulary. If your program's logic findings deserve that scrutiny, let's talk.

Keep reading
The Triage Brief

New articles, straight to your inbox.

Practical triage writing, published a few times a month. Unsubscribe anytime.

Or grab the RSS feed.

Drowning in unread reports?

Lease an expert triage team that validates, reproduces and rates every submission, so your engineers only see signal.

Get a triage team