There is an asymmetry at the heart of external attack surface management. You maintain an inventory of what you think you run. An attacker enumerates what you actually run. Those two lists are never the same, and the gap between them is where most external compromise begins.
The gap is rarely caused by negligence. It is caused by time. Organisations acquire companies, migrate platforms, run campaigns, spin up test environments, hire agencies, and change cloud providers. Every one of those events leaves residue on the internet, and very little of it ever finds its way back into a spreadsheet.
Here is what tends to be sitting in that gap.
Subdomains nobody owns any more
Subdomain enumeration is the cheapest reconnaissance there is. Certificate transparency logs, passive DNS, and public datasets will hand an attacker a list of your subdomains in seconds, including ones that were never meant to be found.
The dangerous case is the dangling record: a CNAME still pointing at a cloud service, storage bucket, or SaaS tenant you no longer own. Anyone who can claim that resource now serves content from your domain. That is a subdomain takeover, and it converts directly into credential phishing that passes every visual check a user has been trained to make.
Marketing subdomains, old campaign sites, and staging hosts left behind by a migration are the usual suspects. So is anything a departed agency set up on your behalf.
Management interfaces that were never meant to be reachable
Admin panels, database ports, remote access services, developer tooling, message brokers, and monitoring dashboards get exposed by accident constantly. A security group edited during an incident and never reverted. A firewall rule added for a vendor’s proof of concept. A device that shipped with its management interface bound to every address.
These are found by mass internet scanning within hours of appearing, not weeks. The window between exposure and discovery by someone else is far shorter than most teams assume, and it does not depend on how interesting your organisation is.
Cloud assets outside the account you know about
Shadow cloud is not hypothetical. A team with a company card. A proof of concept that quietly became production. An acquisition that came with its own accounts. A contractor’s environment holding a copy of your data. None of it appears in your asset register, none of it is in your patch cycle, and none of it is covered by your logging.
Public object storage deserves a specific mention. The failure mode is rarely a wide open bucket any more. It is a bucket with an overly broad policy, a stale pre-signed URL pattern, or public read on an object prefix that somebody assumed was obscure enough to be safe.
Secrets that left with the code
Credentials in public repositories, API keys in client-side JavaScript, tokens embedded in mobile app bundles, and connection strings buried in old commits. Git history is a permanent record. Rotating a key without rewriting history leaves the old one discoverable, and automated scanners are watching public pushes in close to real time.
Paste sites, package registries, and published container images are all part of the same surface. If your build pipeline publishes an image, anyone can pull it and read your environment defaults.
Certificates as a map of your estate
Certificate transparency is a public log by design. Every certificate you issue announces the hostname it covers. This is good for the ecosystem, useful to you, and simultaneously a free map for anyone who is interested.
Expired certificates matter for a different reason. They signal an asset that is no longer being maintained, which is exactly the asset an attacker wants to find. An expired certificate on a service that is still answering is one of the more reliable indicators of an orphaned system.
The edges you do not operate
Your attack surface includes the parts of it that belong to someone else. A payment redirect, an embedded widget, a marketing script, a partner portal authenticating against your identity provider. When those are compromised, the impact lands on your domain, your users, and your incident.
Third-party JavaScript on a page that handles authentication or payment is the highest-leverage version of this problem. It is also one of the few areas where a simple control pairing, subresource integrity plus a content security policy, buys a large amount of protection for very little effort.
How to run your first outside-in pass
- Start from what is public, not from your inventory. Pull certificate transparency records and passive DNS for your registered domains before you look at any internal list.
- Resolve everything, then check what answers. A record that resolves to infrastructure you do not control is your first priority.
- Scan the resolved hosts for open services rather than assuming the firewall is configured the way the diagram says.
- Diff the result against your asset inventory in both directions: things you run that you did not know about, and things in your inventory that no longer exist.
- Audit your registrar and DNS provider accounts for domains you forgot you own, including defensive registrations and common misspellings.
- Search public code hosting and package registries for your domains, internal hostnames, and email patterns.
Do the whole pass before fixing anything. The value of the first run is the shape of the gap, not the individual findings.
Why once is not enough
An attack surface is not a state, it is a rate. Every deployment, every DNS change, every new SaaS trial moves it. A point-in-time assessment tells you about a day that has already passed, which is why the annual penetration test has never been a substitute for this work.
The practical target is not zero exposure, which is unachievable for any organisation that ships software. It is a short interval between something appearing on the internet and you knowing about it. If that interval is measured in days rather than quarters, you are ahead of the enumeration that is already running against you.