Anatomy of a Breach: How Five Small Gaps Become One Big Incident
None of what follows is one specific real incident. It's a composite, built from patterns that show up repeatedly across real security research and disclosures, because that's a more honest way to…
None of what follows is one specific real incident. It's a composite, built from patterns that show up repeatedly across real security research and disclosures, because that's a more honest way to make the point than pretending to know the internals of a breach we didn't investigate. But every individual step below is a documented, common failure mode. They illustrate one way multiple weaknesses can be chained together in a real attack.
That's the part most people get wrong about breaches. Nobody finds one catastrophic flaw and walks straight into your database. They find five small ones, each individually survivable, each individually the kind of thing that gets triaged as "low priority, fix later," and they walk through them one at a time until the last one lets them out the other side with everything.
Step 1: The Forgotten Subdomain
Eight months ago, marketing spun up promo.yourapp.com on GitHub Pages for a campaign. The campaign ended, someone deleted the GitHub repo during a cleanup sprint, and the DNS record pointing at it never got removed. Nobody flagged it, because nothing about the site visibly broke.
An attacker running routine reconnaissance against your domain can discover the dangling CNAME through Certificate Transparency logs and DNS enumeration. They determine that the abandoned GitHub Pages resource can be claimed and register a new repository with the name the old Pages site used. promo.yourapp.com, your real domain, now serves whatever they put there.
Step 2: The Convincing Phishing Page
What they put there is a login page that looks exactly like yours. It doesn't need to be a perfect clone. The page is hosted on a legitimate subdomain, and it may also have valid HTTPS, making the phishing page harder for users to distinguish from a legitimate page. An email goes out to a list of your users: "Your session expired, please sign in again," linking to promo.yourapp.com/login.
A percentage of recipients click it. Some percentage of those enter their credentials into the fake form. The attacker now has usernames and passwords for real accounts, obtained through a phishing page hosted on infrastructure that appeared legitimate to the recipients.
Step 3: The Cookie That Was Never Protected
Stolen credentials alone don't guarantee access, if MFA is properly enforced on the account, a password on its own isn't enough. But your application's session cookie was set without the HttpOnly flag, an oversight that predates most of the team currently working on it. That flag exists specifically to stop JavaScript from reading document.cookie.
If an application relies on session cookies that are accessible to JavaScript, an XSS vulnerability on a relevant page can expose those cookies. Whether a compromised subdomain can access or influence session state depends on cookie scope, browser origin boundaries, CORS, and the application's architecture, a subdomain takeover doesn't automatically hand over every application's session cookie by itself. In this scenario, a low-severity XSS vulnerability that nobody prioritized fixing is reachable from a page where the session cookie is exposed, allowing the attacker to read the token.
Step 4: The Firewall That Wasn't in the Path
Your team deployed a WAF specifically to catch exactly this kind of probing, SQL injection attempts, suspicious request patterns, automated scanning. It's correctly configured and actively blocking malicious traffic aimed at your domain.
It's also irrelevant here, because the attacker isn't sending requests to your domain. Months earlier, before the WAF was added, a subdomain got created that pointed directly at the origin server's IP address, and it was never cleaned up either. That IP is still discoverable through DNS history and old certificate records. The attacker sends their requests straight to the server, bypassing the WAF entirely. Every rule it enforces never gets a chance to run.
Step 5: The Database With No Password
With access to the application environment through the compromised origin, the attacker starts probing what else is reachable from that network. A Redis instance is listening on a network-accessible interface, configured months ago for local caching during development and never firewalled off when the app went to production. A network-accessible Redis instance is insufficiently protected by authentication and network controls. In this scenario, redis-cli can connect without requiring a password.
At this point, the attacker may have access to sensitive cached data and, depending on the Redis configuration and application environment, potentially additional paths toward compromise. What started as one forgotten DNS record has escalated into a serious incident, and none of the five steps that got there involved anything more sophisticated than noticing what was already publicly visible.
Why This Chain Actually Works
Several individual steps in this sequence might be treated as lower-priority findings when viewed in isolation. A dangling DNS record isn't an active exploit. A missing HttpOnly flag isn't a breach by itself. An exposed origin IP doesn't do anything until something else finds it useful. An open Redis port with no traffic hitting it looks harmless in a vulnerability scan that doesn't test what's actually reachable through it.
That's exactly why chains like this work. Nobody is required to find one severe bug. They're required to find several unrelated, individually low-priority gaps and notice that each one removes a barrier the next step needed. Removing one of these links can break this particular attack path, although an attacker may still find another route if other weaknesses remain. Fixing none of them, because each one alone looked survivable, is how the whole thing stays open for months.
Breaking the Chain
Every step above maps to a specific, checkable thing:
- The dangling subdomain gets caught by searching Certificate Transparency logs for your domain and checking whether every subdomain still resolves to something you actually control.
- The missing HttpOnly flag gets caught by checking your Set-Cookie headers directly, this is often a small application or configuration change once it's noticed.
- The exposed origin IP gets caught by checking DNS history and certificate records for any A record that points directly at your server instead of through your CDN or WAF.
- The open Redis port gets caught by checking what's actually listening on your server's public IP beyond the ports you expect to be open.
None of these require deep expertise individually. What they require is treating each one as worth fixing on its own, rather than waiting for it to be part of something worse before it gets attention. By the time a chain like this completes, it's too late to have this conversation about any one step in isolation.
Frequently asked questions
Final Thoughts
The uncomfortable truth about most real breaches is that they don't require a genius attacker or an unpatched zero-day. They require patience and a willingness to check the boring things: what subdomains still resolve, what headers are actually being sent, what ports are actually open. Most of that information is already public.
The defense isn't fundamentally different. It's the same checking, done first, by the team that owns the infrastructure instead of by whoever finds it later. Five small gaps take five small fixes. One completed chain takes an incident response.
How FlawPilot helps
FlawPilot finds security and quality issues in your AI-built app and shows you how to fix them. It checks your deployed site across security, performance, infrastructure, and SEO, and scans your source code for vulnerabilities, hardcoded secrets, and vulnerable dependencies.
Every finding is prioritized and explained in plain English, with the actual fix: the configuration change, DNS record, security header, or code change needed. For supported findings, AI-powered guidance adds step-by-step instructions and suggested code fixes.
Connect your Git provider to scan your repository alongside your live site, so application findings, code vulnerabilities, secrets, and dependency issues all land in one place.
It fits your existing workflow too: a REST API for scores and findings, an embeddable security badge, and an MCP server so tools like Claude, Cursor, or ChatGPT can read your findings and help you work through them.
The boundaries are clear: the public website scan reads only publicly accessible signals, with no agent or credentials required, and source-code scanning is opt-in and read-only. Fixes are never applied or merged without your review.
Verify your AI-generated app is production-ready.
117 security checks in 60 seconds - free, no account needed.
Scan one page
Enter a URL - no account, no install.
Run a Site Health check
Requires a free accountCrawls every page we can reach and scores each one, so a slow template deep in the site stops hiding behind a healthy homepage.
Scan your source code
Requires a free accountConnect a Git provider to check for vulnerabilities, secrets, and risky dependencies.