Displayed Total Versus Submitted Total: Reading a Checkout Form

Security Fundamentals Level 3/4 ~4 min September 10, 2026

The challenge

A checkout page shows a clean, confident summary: one plan, one price, one total due today. The number the customer reads and the number the billing service actually charges are computed in two completely different places, and on this page they have drifted apart. Look at the rendered page first and note the total it advertises, then switch to View source and read every field the form will actually submit. A comment in the markup spells out how the server adds the charge up. Work out what this form really charges when the customer presses Confirm and pay, and submit that number.

What you'll learn

  • Compare what a page renders against what its form actually submits
  • Identify hidden input fields and the values they carry
  • Apply a stated server-side summation rule to form data
  • Distinguish priced fields from metadata fields in a form
  • Explain why prices must never be computed from client-submitted values

Skills tested

HTML source inspectionClient-side trust analysisPayment flow review

Prerequisites

  • Reading basic HTML form markup
  • Understanding that hidden inputs are submitted

How it works

A checkout page is two calculations wearing one interface. The template renders a total for a human to read, and the form assembles a set of fields for a billing service to charge. Nothing forces those two numbers to agree, and when they drift apart the interface keeps looking correct, because the part the customer can see is the part that was never authoritative.

The Preview tab shows a single subscription and Total due today: 290 EUR. That string lives in the page body. It is not an input, so it is never submitted and the server never sees it.

View source shows what will be. A comment states the billing rule outright: the service charges plan_price plus every addon_* field plus promo_credit. Four fields match that rule: plan_price at 290, addon_priority_support at 120, addon_onboarding at 450 and promo_credit at -60. Summing them with the sign intact gives 800. Three further hidden fields, plan_id, currency and csrf, carry no price and fall outside the rule.

So the page advertises 290 and the form charges 800. Neither component is malfunctioning; they simply disagree, and the disagreement is invisible from the rendered page. The same architecture fails in the customer's favour just as easily, because a form that carries its own prices is a form the client can edit before submitting. Displaying a price is a presentation concern; deciding a price is a server concern, and this page has confused the two.

Common mistakes

  • Answering 290. That is the rendered string. It is not a form field and is never submitted.
  • Answering 860. That drops the sign on promo_credit, which is -60 and reduces the charge.
  • Answering 570. That adds the plan and one addon while missing addon_onboarding. Both addon_* fields count.
  • Including plan_id, currency or csrf. They are hidden but carry no price, and the stated rule does not cover them.
  • Stopping at the Preview tab. Every priced field on this page is hidden, so the rendered view alone cannot answer the question.
  • Adding VAT. The footer states prices already include it, and no tax field is submitted.

How to defend against it

The rule is simple and absolute: the browser may display a price, but it must never supply one.

  • Send identifiers, not amounts. The form should submit plan_id and a list of selected addon ids, and the server should look every price up from its own catalogue.
  • Compute the total server-side and render the displayed figure from that same computation, so one number cannot drift from the other.
  • Treat any priced field arriving from a client as untrusted input, and reject a request that carries one at all rather than trying to validate it.
  • Bind the quote. Issue a server-side quote or cart id with the amount attached, and charge against that id.
  • Reconcile continuously by alerting when the amount charged differs from the amount quoted for the same cart, which catches this class of bug in production.
  • Cover it in tests, asserting that the charge produced by a checkout equals the total the page displayed.

Full solution

Pro and Max members unlock the complete step-by-step walkthrough.

Go Pro

Community stats

172 completions
88% success rate
Hodanalo First blood

Related Daily Hacks

25,000+ Hackers 100+ Labs & Courses Free
Start Hacking Free