Dmitriy Kononov
Let’s talkContact

News and analysis

A business logic flaw: the scanner can't see it, but it breaks bookings and carts

GitLab, Cloudflare and Shopify on the holes scanners miss: someone else's order by ID, a role from JSON, a price from the client. How I close them in bookings and orders.

The most expensive holes in a booking site or an order system look like correct code. The server returns an order by its number and doesn't ask whose it is. The “role” field in a profile accepts whatever the client sent. The browser calculates the total, and the server believes it. A security scanner stays silent here because there is nothing for it to find: the check is missing, and missing code doesn't match a pattern. This week GitLab, Cloudflare and Shopify wrote about this, and I have something to add from car rental and coffee orders.

What came out

On October 20, GitLab introduced the Business Logic Security Analyzer, for now in early access for Ultimate customers on GitLab.com. Their starting point is right: broken object-level authorization sits first in the OWASP API Security Top 10, and ordinary SAST doesn't find these things. Three examples from the post: an endpoint takes an order ID from the request and returns the order without checking the owner; a role field accepts any JSON; the user ID is a sequential integer. Separately, each is valid code; together, it is every order of every customer plus administrator rights. The analyzer reads the whole repository and checks each handler against a model of who can do what. In their demo it finds a refund_order that sets refunded=1 without checking the owner and flags it as CWE-639.

On October 21, Cloudflare added full-transaction inspection to its WAF: the request is examined together with the response, and a rule can block the server's response before it reaches the requester. The example from the post: a request for the file ../../config/database.ini proves nothing by itself, while a 200 response with the database login and password proves everything. It is available to everyone, including the free plan. One caveat from the same post: the response can be blocked, but what the server has already done can't be undone. By that point the refund on someone else's order has already gone through.

On October 20, Shopify asked all app developers to spend this week on security: run the new check, move to expiring access tokens, which will soon become mandatory for public apps, review request logs by client IP, and turn on two-factor protection everywhere. The check itself came out on October 15 as the shopify app security check command in the Shopify CLI: it runs locally and looks at code, configuration and dependencies, and partners who tried it found gaps in authentication and in data isolation between stores. The tool's code is open.

And news from the other side of the counter. On October 20, CNews relayed a warning from Kaspersky Lab: vulnerabilities in wireless barcode scanners can give access to warehouse computers, and from there to order processing and shipping; the same path exists through handheld data terminals and thermal printers.

What it looks like in car rental

Take a car rental website. A customer books a car, gets a link to contract number 1041 and, out of curiosity, opens 1040. If the server returns a contract by its number and doesn't check whose it is, the customer is reading another customer's passport details. Then they notice that the payment request carries a price field, and change it. If the browser calculates the total and the server saves whatever arrives, the car drives off for half price. Neither of these holes looks like a bug in the code.

The conclusion: the rules about who may do what and how the total is calculated must live on the server and run there. The client only shows the result.

How I do it

On the car rental site in Cape Town, which I took to a full booking cycle over 2025, the booking, the documents, the signatures and the inspection are linked in one chain. Payment is verified from a screenshot attached during the process; that is a check by image, not a reconciliation with the bank, and I say so plainly.

In the “Coffee Together” service the rules are stricter, because it is employees' money. The gateway on Node.js strips the identity headers sent by the client and determines the user itself from a signed HttpOnly cookie, so “I'm the admin” in a request means nothing. The order form has no prices: the total appears only after the organizer checks it against the real cart at the supplier. An order becomes paid only after the organizer confirms the money arrived, and the service allows the “Ordered” mark only after every payment has been checked and the order is in fact placed with the supplier. Only a fully received order can be handed out. Each transition is a check on the server, and when such checks are missing, that is exactly what a scanner can't see.

What I would do

Write out every entry point: pages, API, webhooks, imports from spreadsheets, scanners in the warehouse. For each one, answer who has the right and to which records.

Check that the server itself verifies the owner of every object it returns by ID. A second account and someone else's order number in the address bar find this in five minutes.

Calculate and change totals, discounts, status and role only on the server. Accept fields that came from the client by allowlist.

Describe order statuses and the transitions between them as rules: from which state to which, and after which check.

Review the logs by IP and by account, as Shopify advises.

On checks, statuses and permissions: the article Business logic: rules, statuses and permissions. By area: a customer-facing product tied to the business and API integrations with clear rules for passing data. The systems from this text are described in the cases of the car rental in South Africa and “Coffee Together”. From neighboring reviews: customer portal sign-in: passkeys, SSO and a passwordless link, stores preparing storefronts for AI agents and zero trust for a 30-person company; earlier I wrote about the cart before payment and webhook security. If your order system has an ID in the address bar and a total the client sends, tell me how it is set up, and I'll tell you what to check first. Discuss your task.