Reconvio
Zpět na blog
Security 5 min čtení

The scanner said the site was clean. Then I read the code.

A deep audit of one platform turned up 40 issues — four of them critical. Not one of the four would show up on an automated scan. Here's why, and what it means for your site.

Marek Křivan · 17. července 2026

A while ago I audited a mid-sized commerce platform — a real business, real customers, real money moving through it. I can't name it; the work was under NDA, so call it the platform. Before I got involved, it had been through the usual automated security tooling. The scans came back mostly green.

The full audit found 40 issues. Four of them were critical — the kind where a single mistake hands an attacker the whole database. And here's the part worth sitting with: not one of those four would ever appear on an automated scan. They weren't hiding. They were just the kind of flaw a scanner is built not to see.

This is the most useful thing I can tell you about website security, so let me show you what those four were.

What the platform was

Nothing exotic. A multi-tenant setup — many separate shops running on one shared backend — with a Go backend, a Vue frontend, a handful of internal services talking to each other, all running in Docker. A modern stack, competently built. The kind of architecture thousands of teams ship.

The audit combined manual code review with the standard industry checklists: the OWASP API Security Top 10, the CWE/SANS Top 25, the CIS Docker Benchmark. Seventeen separate analytical passes. That depth is the whole point — it's what a 30-second scan is not.

The four that mattered

1. A front door with no lock. The service holding every shop's data — product catalogs, prices, stock, orders — accepted commands from other services without ever checking who was asking. More than sixty internal methods, none of them verifying the caller's identity. Someone had even left a note in the code admitting it: the service token was there, but "catalog does NOT gate it." Translation: any attacker who got a foothold anywhere inside the network could read, change, or delete every shop's data at once.

2. Everything in cleartext, on the inside. The internal services talked to each other with encryption explicitly turned off. Passwords, customer personal data, application secrets — all crossing the internal network in plain text. The assumption was "the inside is safe." It never is. One compromised container, and an attacker sits quietly in the middle reading all of it.

3. The customer who could crown himself. In the admin interface, one function set a user's role — but never checked whether the person calling it was allowed to. So any logged-in customer, with the lowest possible privileges, could send one crafted request and promote themselves to owner. Full takeover of accounts that weren't theirs.

4. The button that suspends every shop. A sibling of the last one: another admin function changed an account's status with no permission check. An attacker could walk through the account IDs and flip every shop from "active" to "suspended" in a loop. Instant, self-serve denial of service against the entire platform.

Why a scanner can't see any of this

Automated scanners are pattern matchers. They're very good at finding the known shape of a problem: an out-of-date library with a published vulnerability, a missing security header, a file that shouldn't be public. If the flaw has a signature, a scanner will usually catch it — and you should absolutely run one, because those flaws are real and common.

But all four criticals above are broken access control — the code runs perfectly, it just trusts the wrong person. There's no malformed input, no known-bad string, no signature to match. The function does exactly what it was written to do. The bug is that nobody told it to check who was calling. To see that, you have to understand what the code is supposed to mean — and meaning is exactly what a text-matching tool doesn't have.

That's not a niche problem. Broken access control sits at the top of the OWASP list for a reason: it's everywhere, it's devastating, and it's close to invisible to automation.

The most expensive line in the audit

Here's the twist. The plaintext-internal-traffic decision wasn't an accident. The team had written it down, on purpose, in an architecture document: we're turning off internal encryption to gain throughput — but every state-changing method must still authenticate the caller.

They knew. They wrote the safeguard into the plan. And then, in the actual code, that safeguard was marked "optional follow-up" and never built.

The flaw wasn't ignorance. It was drift — the gap between the architecture everyone agreed to and the code that actually shipped. No process ever checked that the two still matched. That gap is where a lot of serious breaches quietly live, and no scanner measures it.

The trap I want to warn you about

When you get a finding like these, the tempting move in 2026 is obvious: paste it into an AI model, take the patch it writes, ship it. For a missing header, that's genuinely fine — go ahead.

For something like broken authorization across a dozen interconnected services, it's a trap. An AI patching one file at a time, without holding the whole system in its head, tends to close the reported hole and open a quieter one somewhere else — a new trust assumption, a check that looks right but fires in the wrong place. The audit's own conclusion said this plainly: fixes at this level need a person who understands the entire architecture, not a snippet generated in isolation. Generative tools are a fantastic accelerator for drafting a fix. They are not a substitute for the judgment that decides whether the fix is safe.

What this means for your site

Your site is probably not a fifteen-service platform. Most aren't. But the blind spot scales all the way down.

An external scan — including the free one I built — is fast, and it catches the surface layer where a huge share of real incidents actually start: an exposed .env file, missing security headers, weak TLS, a dependency with a known hole, an admin panel open to the internet. That layer is worth checking today, because those mistakes are embarrassingly common and genuinely dangerous.

What an external scan cannot tell you is whether your "admins only" endpoint actually checks who's calling, or whether your app trusts a request it shouldn't. That's the layer this audit was about, and it's the layer that needs a human looking at the logic.

So do both, in order. Start with the surface — it's thirty seconds and it's free — and fix what comes back. Then, if your site holds real money or other people's data, get someone to read the parts a scanner was never able to.

The scan tells you the doors are locked. It can't tell you the lock is wired to the wrong door.

Zjistěte, co váš web prozrazuje

Spusťte zdarma audit a za půl minuty máte konkrétní nálezy — bez registrace.

Zkontrolovat web