Five surfaces every AI product team forgets to scan.
Stale staging hosts, debug endpoints, public buckets, source maps, and admin paths: the five most-missed exposures we find on AI product companies, and how to look for them.
AI products ship fast. A model endpoint, a thin web app around it, a few integrations, a launch post. The security conversation, when it happens, is almost always about the model: can it be jailbroken, does it leak the system prompt. Those matter, and we have written about how we test them. But when we look at what actually gets an AI company breached, it is rarely the model. It is the long tail of ordinary web exposure that grew up around it while everyone was looking at the prompt.
These are the five surfaces we see missed most often in the field, roughly in the order we find them.
1. Stale staging hosts and dangling DNS
Every fast-moving team leaves hosts behind: staging-v2, demo-old, api-canary, the preview deploy from a feature branch that shipped months ago. Some still run an older build with a vulnerability that production patched. Some point at infrastructure that no longer exists, which means anyone who can claim that cloud resource name now owns a subdomain of yours, complete with the trust your users and your cookies extend to it.
What to look for: subdomains whose CNAME targets no longer answer, hosts serving an older version string than production, and anything with staging, dev, test, or old in the name that still returns 200.
2. Debug endpoints that survived the launch
Framework debug tooling is enormously useful in development and catastrophic in production. We regularly find Spring Boot actuators with /actuator/env and /actuator/heapdump open, Django debug pages echoing settings, Laravel Telescope, Flask debuggers, and Next.js or Vite dev servers reachable on an alternate port.
The AI-specific variant is model and agent tooling: Jupyter kernels left on a public interface, Gradio and Streamlit demo apps with no auth, vector database admin consoles, and evaluation dashboards that show real user prompts. GraphQL introspection and auto-generated OpenAPI docs round out the list. None of these are vulnerabilities in the CVE sense. All of them hand an attacker a map.
3. Public object storage
Training data, fine-tuning sets, evaluation transcripts, uploaded documents for retrieval, model weights, generated images. AI products move a lot of files, and files end up in buckets. A bucket with public listing enabled is the single highest-impact misconfiguration we find, because the contents are so often exactly the data the product promised to protect.
- Bucket names guessable from the product or company name, with listing enabled
- Objects that are world-readable even when the bucket itself is private
- Pre-signed URLs with multi-year expiry embedded in front-end code
- Backups and database exports left in the same bucket as public assets
4. Source maps and the secrets inside bundles
A production JavaScript bundle with its source map published is a free copy of your front-end source. On its own that is a leak of intellectual property and a head start for anyone probing your API. Combined with the habit of putting configuration in the client, it becomes a credential leak: third-party API keys, internal endpoint URLs, feature flags that reveal unreleased functionality, and occasionally a model provider key that was supposed to be server-side. We cover the mechanics in Exposed .env files, source maps and API keys.
The scanner reads every bundle it can reach, follows sourceMappingURL comments, and pattern-matches for high-entropy strings and known key formats. A hit is verified with a read-only check where the provider offers one, so the report says whether the key is live rather than just present.
5. Admin paths and leftover tooling
The last surface is the one nobody thinks of as a surface: the internal tools. /admin, /internal, /ops, the queue dashboard, the feature-flag UI, the prompt management console. These start life behind a VPN and drift onto the public internet when the deployment changes and nobody updates the ingress rule.
They are easy to find because they are boring and predictable. The scanner tries the common paths, follows links from the ones it finds, and reports anything that returns content without an authentication challenge. An admin login page that is reachable is a Low finding. An admin dashboard that renders without one is a Critical, and it is verified by fetching an authenticated-only resource before it is reported as such.
What do all five have in common?
None of these require a clever attacker. They require someone who looked. The reason they survive is that they live outside the application code that gets reviewed, outside the model that gets red-teamed, and outside the single production hostname that gets pen-tested once a year.
The fix is the same in every case: enumerate the whole public surface, not just the front door, and do it on a schedule, because the surface changes every time someone ships. That is the job Pythorix was built to do. Add a domain, and the scanner walks subdomains, routes, bundles, and storage on every run, diffs the result against last time, and tells you what appeared. The discipline has a name, and we explain it in What is external attack surface management?.
Frequently asked questions
What is a dangling DNS record?
A DNS record, usually a CNAME, that points at a cloud resource which no longer exists. An attacker who registers that resource name takes over the subdomain, inheriting the trust browsers and cookies extend to your domain.
Are exposed debug endpoints a vulnerability?
Not usually in the CVE sense, but they leak configuration, environment variables, heap dumps, and internal routes that make every other attack easier. Endpoints like /actuator/env or an open GraphQL introspection should be treated as High severity exposure.
How do I find out if my S3 bucket is public?
Request the bucket URL anonymously. If it returns an XML listing, listing is public. Also check individual objects, since objects can be world-readable even when listing is disabled. An external scanner does both checks for every bucket name it discovers in your code and DNS.
How often should I scan my attack surface?
At least after every deployment, and on a daily schedule for production domains. The surface changes every time someone ships, so a quarterly or annual scan misses most of the window in which an exposure is live.