A shop can accept a request that is correctly formatted yet violates the intended business rule. Business logic is the set of rules governing a workflow, such as when payment permits dispatch. A workflow is a sequence of actions; an invariant is a condition that must remain true throughout that sequence.
The coupon cards use the invariant “one coupon use per order.” A valid number and a positive total do not prove the workflow is valid. The server must enforce the rule using its stored order state instead of trusting a total supplied by the browser.
Before you begin
- Recommended first
- Notes: scope, command, result, time, HTTP methods, headers, status codes, cookies, How a web app is put together, Same-origin policy, Command injection
- Estimated time
- 16 min reading, 12 min activity. Setup and optional practice may take longer.
- Where you work
- Read the original fictional requests, source fragments and state tables in a current desktop or mobile browser. The required activity needs no server, database, account or installed security tool. Do not send the printed requests to any service.
- Without a lab
- Use the complete printed evidence to trace the data or state on paper. Write the decision, the fact supporting it and one limit of the model, then compare with the activity rubric. This does not establish live service behavior. Reading works without JavaScript. Checking requires JavaScript and a secure browser context; saving also requires usable browser storage.
After this lesson you can:
- State the once-per-order rule.
- Mark the second SAVE2 on order 17 and the second CLIP on order 18.
01Example
This fictional shipping workflow demonstrates an invariant before you apply the coupon rule in the activity.
Rule: dispatch only after payment is confirmed.
Order 26: payment unpaid.
Proposed action: dispatch.
Decision: refuse until payment is confirmed.
A correctly formatted dispatch request does not change the rule.02A valid row can break the order
In the worked dispatch example, the payment state is unpaid. Accepting a dispatch request would violate the payment-before-dispatch invariant even if the request has the right fields. The activity applies the same method to a different workflow: count uses of a coupon within each order, then compare them with the stated limit.
The impact depends on the rule: a shop could lose money or release goods without the intended approval. Enforce the invariant on the server at the state-changing operation, including concurrent requests. The fictional event rows show their own sequence; they do not establish the rules of any real shop.
Apply a once-per-order coupon rule to a second apply row, even when each row looks like a normal price change.Model. A teaching model drawn by hand. It shows the idea, not real tool output.
Read the full explanation below.
Rule: dispatch only after payment is confirmed.
unmet · Order 26: payment unpaid.A correctly formatted dispatch request cannot satisfy payment-before-dispatch.
A valid-looking request cannot override the business rule; no order is dispatched.
A correctly formatted dispatch request cannot satisfy payment-before-dispatch.
Follow the explanation
- A correctly formatted dispatch request cannot satisfy payment-before-dispatch.
- The rule must be enforced at the state-changing operation; this model supplies no later payment.
Read every state and value
1. A correctly formatted dispatch request cannot satisfy payment-before-dispatch.
- Case
- unpaid
- Conditions inspected
- Payment before dispatch
- Decision shown
- Yes
2. The rule must be enforced at the state-changing operation; this model supplies no later payment.
- Case
- invariant
- Conditions inspected
- Payment before dispatch
- Decision shown
- Yes
03Mark order 18
Read the evidence before comparing your reasoning with the activity rubric. Count apply rows, not the size of the discount.
Follow the separate Order 18 coupon historyModel. A teaching model drawn by hand. It shows the idea, not real tool output.
Read the full explanation below.
A coupon may be applied once on an order.
met · 18,2,apply CLIP,3,12 — first CLIP on order 18.The server records the use before it reduces the total.
met · Record the use before reducing 15 to 12.The first CLIP use on order 18 fits the supplied invariant.
A valid-looking request cannot override the business rule; no order is dispatched.
The first CLIP use on order 18 fits the supplied invariant.
Follow the explanation
- The first CLIP use on order 18 fits the supplied invariant.
- The positive running total 9 does not make a second CLIP valid.
Read every state and value
1. The first CLIP use on order 18 fits the supplied invariant.
- Case
- first
- Conditions inspected
- Once per order · Record before reducing
- Decision shown
- Yes
2. The positive running total 9 does not make a second CLIP valid.
- Case
- second
- Conditions inspected
- Once per order · Record before reducing
- Decision shown
- Yes
Order rules for the club shop. Prices are fictional units.
1. A coupon may be applied once on an order.
2. The server records the use before it reduces the total.
3. A second apply row for the same order and coupon is invalid even if the price is positive.
4. A different order may use the same coupon code once of its own.
order,step,action,amount,running_total
17,1,add lamp,20,20
17,2,apply SAVE2,2,18
17,3,apply SAVE2,2,16
18,1,add cable,15,15
18,2,apply CLIP,3,12
18,3,apply CLIP,3,9
19,1,add lamp,20,20
19,2,apply SAVE2,2,18
- Write the rule about how many times a coupon may apply to one order.
- Count CLIP rows on order 18 and SAVE2 rows on order 19.
- Check: order 18's third row is a second CLIP, so it breaks the rule. Order 19 has one SAVE2, so that order still fits. Order 17 is the worked double SAVE2.
- Stop. Do not submit these codes anywhere but this card.
04Optional challenge
Say where the server should enforce the once-per-order rule. The rubric is: before it reduces the total, on the server, using the recorded uses. About ten minutes.
05Fresh cases for the checks
Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.
Coupon case A: fresh ordered traceOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
Rule: a coupon may be applied at most once per order; a different order has its own allowance.
R1: order 31 applies LEAF, total 19.
R2: order 32 applies LEAF, total 24.
R3: order 31 applies MINT, total 17.
R4: order 31 applies LEAF, total 15.
Different coupon codes have independent once-per-order allowances in this model.
Coupon case B: independent transitionOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.
Before request: order 45 has used coupon FOLD once.
Request: apply FOLD again.
Requested discount is smaller than the remaining positive total.
Server rule: check recorded uses before reducing total.
06Explain your evidence
Optional written self-check: explain one decision using the supplied case. No tool run is required.
Check your explanation: track each order/coupon pair; cite the first repeated pair; explain why positive totals and valid syntax do not establish workflow validity; enforce the recorded invariant at the server transition.
07Common mistakes
If you mark order 19 invalid, you counted a single use. The third row is order 18.
If you call 16 a bug because it is smaller than 20, you skipped the rule. The first discount is allowed.
If you let the browser be the judge, the card's record is the server's apply rows.
References
- PortSwigger: Business logic vulnerabilities
Explains the failure mechanism and prevention. Use it for further reading after reasoning from this page's original model; a topic page is not evidence that a lab was launched.