23 October 2026 · Gilles Maury
Every test passed. The security review still found four flaws.
I built a complete site for a barber shop: trilingual, with real online booking, a calendar, confirmation emails, and an admin area where the owner changes their own copy, prices and photos. All of it on shared hosting costing a few euros a month.
Before putting it online, I asked for a security review. I expected a formality: a hundred-odd automated tests green, over a thousand assertions, an independent reviewer who had signed off the design at 100/100, and security checks running on every change to the code.
The result: no critical flaw, but one high-severity flaw and three medium ones.
That's what this article is about. Not speed — today's tools let anyone write code quickly. What actually matters is what happens between "it works" and "I'm putting it online".
Why the tests couldn't have found them
The one sentence to keep, if you keep only one:
Tests check that the site does what you planned. A security review looks for what you didn't plan.
Those are two different jobs, and the second doesn't follow from the first. None of the four flaws was visible to the tests, because none of them was expected behavior gone wrong. Every one of them was correct behavior turned to another use.
For a site holding customers' names, phone numbers and email addresses, the review isn't a nice-to-have: it's the minimum before going live. If you're having a booking site built, that's the question to put to whoever builds it — not "is it tested?", but "has anyone tried to break it?"
Four lessons, without the how-to
Every flaw was fixed before going live, each with a test. What follows is the mechanism, not the recipe — the code serves as a base for other projects.
A safeguard can turn against the person it protects. Locking the account after several wrong passwords exists to protect the owner. As it was tuned, anyone could use it to lock them out, emergency procedure included. The question to ask of every safeguard: what if the attacker used it against the user?
A counter that reads, adds one, then writes back stops counting when everything arrives at once. The per-hour booking limit held perfectly in testing, and gave way as soon as requests were sent simultaneously. The increment has to happen in the database, in a single operation. It's a common design error, invisible on review, and only a concurrency test reveals it.
A half-finished step can leave a door open. A change-of-phone screen, abandoned midway, could leave the account without its second factor — the password alone was then enough to get in. Any multi-step procedure has to be designed for the case where the user closes the window in the middle.
For a local business, availability and reputation weigh as much as confidentiality. A calendar that can be filled with junk, or a domain flagged as a spam sender, sinks a shop just as surely as a data leak. Any field echoed into an email sent to an address chosen by a stranger is a potential weapon. People rarely think of it while focusing on database injection.
What to demand from a security review
Whether it's run by a person or tooled up, a useful review looks nothing like a compliance audit. Here's what worked, and what you can insist on:
- A change of stance, not a verification. The instruction isn't "check that it's safe" but "find how to abuse it". The question stops being does it work and becomes how do I subvert it.
- A split by attack surface. Whoever looks at everything skims. Three separate areas — sign-in, the public side, administration and deployment — each dug into on its own.
- Concrete scenarios, not best practices. For each flaw: the file, the line, the conditions, the impact, the severity, the confidence level. A report that advises "add a firewall" isn't a report.
- Proof that the path is actually reachable. Otherwise you drown in false positives. One report described a flaw in a restore function… that doesn't exist.
- A read-only reviewer. They report, they don't fix. Fixing is separate work, with its own tests.
- The business context. "Small shop, single owner, customer data" is what prompts thinking about a flooded calendar and spam, rather than only textbook attacks.
- A review that also says what's left. Three weak points were carried forward, written down with their reasons. That's precisely what lets you sign off knowing what you're signing. A review that finds nothing and carries nothing forward wasn't done.
And one method rule: never believe a report without checking it against the code. Every finding was re-read before being fixed.
What the checks had already caught
The security review is the last net, not the only one. Before it, nine defects were stopped before production, four of them serious — none by a user, all by a check or a review. They're listed one by one in the repo's report. The most telling:
| Defect | Caught by | Had it got through |
|---|---|---|
| Simultaneous bookings rejected at peak times | concurrency test across 20 processes | lost bookings |
| Install broken by a single ";" inside a translated string | unit test | site impossible to install |
| Nested transactions in the calendar's safeguards | integration test | opening hours impossible to change |
| Owner with no way back in after losing their phone | the independent reviewer, at design stage | owner locked out of their admin |
That last one is worth noting: it was found before a line of code was written. That's what a design review actually costs, and what it returns.
The checks themselves were put to the test too: twenty-two deviations were introduced deliberately into the code, and every one of them turned its check red. That's the verification everyone forgets — a check that cannot fail proves nothing. Same for the flaw fixes: for every test added, the old code was put back to confirm the test really went red.
What went wrong anyway
The most instructive part, and the one that justifies taking the time to check things yourself.
Two minutes after starting the site locally, the booking page showed "Something went wrong". The start command was omitting the encryption key. All the tests passed — because they supplied the key themselves, and no test ever ran the command I actually use. Fixed at the root: a single source of configuration for both the tests and the local start.
It's the most common trap of all: a green test suite proves the code works under the tests' conditions, not under yours.
Before publishing the repository, close to three thousand files had been committed by mistake — dependencies, cache, test images. No secrets among them, but nothing that belonged there either. Cleaned up, then re-checked on a genuinely fresh clone, that is, under the conditions of someone discovering the project.
The architecture, invisible but decisive
This is the part a demo never shows, and probably the most important one for you.
It isn't a brochure site with a form: it's an application built from the first line around separate business domains, with the rules at the center and the technology around them. Four independent domains — access, the storefront, the calendar, notifications. At the center, pure rules: no two customers in the same chair at the same time, cancellation allowed up to two hours before. They know nothing of the database, the web or email. Around them, interchangeable adapters: you can change database or email provider without touching the rules.
And it isn't just a stated intention: an automated check rejects any commit that would put technical code into the business core.
Why it concerns you: capabilities can be added one at a time without breaking what exists. After booking, the same shop can take on stock management, a loyalty card, the till, invoicing, staff scheduling — each as a new domain wired to the others through clear interfaces. You avoid the classic rebuild on the day "the little site" is no longer enough.
A full management system is more than code — statutory accounting, compliant invoicing, support. But the technical foundation is already able to carry it. It's the same separation between what belongs to one project and what gets built once for all of them that I lay out in the map of a deployed product.
What it costs to host
The site runs on ordinary shared hosting: PHP and MySQL, nothing else to administer. Two plans fit (prices observed in October 2026, first year):
- An entry plan, around €2 a month: one site, one database, one email address. A shop's database weighs a few megabytes. Enough for a demo or a launch. Limitation: a single site, so no test environment — you deploy straight to production.
- A mid plan, around €3.60 a month: several sites and databases. That's the one I chose, because it allows a test site alongside production: every update goes through the test site first, and production only receives it once checked.
The advice: entry plan for a demo, the one above as soon as real customers are booking. The code is the same; you move from one to the other without rewriting anything. A comparison of five hosts and the step-by-step deployment procedure are in the repo.
For a startup: the demo becomes the product
This is where I see the real shift. A team that has to show something to customers or investors usually has two options: a pretty but empty mock-up, thrown away afterwards, or full development before knowing whether the idea holds.
There's a third way:
- A product that genuinely works, not a picture: you book, you get the email, the owner changes their prices.
- A few euros a month: you can leave it running while you test the market, without burning cash.
- The look is validated at the demo stage and kept afterwards: early users' feedback lands on the final product, not on a draft.
- The code isn't disposable: domain architecture, tests, decisions on record.
The risk moves. It's no longer whether you can build it, but whether anyone wants it — which is exactly the question a demo is supposed to settle.
What this changes for you
If you're having a site built that takes appointments or holds customer data, three questions are enough to judge the seriousness of what you're handed:
- Has anyone tried to break it, rather than only checked that it works?
- Have the checks protecting your site been put to the test — has anyone verified they know how to say no?
- Is whatever remains open written down somewhere, or were you simply told everything was green?
The whole project is public and MIT licensed: the code, the design documents, the signed release review, the detailed report, and the videos of the eight journeys replayed in a real browser. The method framing all of it is described in the article on reliability.
If you'd like to look at your project in these terms, let's talk.