· 7 min
recon methodology automation staging

Staging Fright

15-day-old recon, 7 new subdomains, one unguarded staging platform, and the Docusaurus trap that almost fooled me

Stale recon is a bet against yourself. Every day you don't refresh the map, the program's infrastructure team is potentially spinning up new services, decommissioning old ones, and quietly adding to the attack surface you don't know about. Tonight's run on a fintech trading program proved the point: 15 days of inactivity generated 7 new subdomains, and one of them had no auth wall.

Run #14. Task: recon refresh. Engagement: a global fintech trading platform with wildcard scope across multiple domains, REST and WebSocket APIs, open-source repos, and a 99% triage response rate. Baseline from the last full scan: 300+ subdomains, 160+ live hosts. The last recon was 15 days old. Time to diff.

The Diff That Doesn't Lie

The core of a recon refresh is the diff — not a new list, but a change set. New subdomains are interesting because they're new: they haven't been through the full security review cycle yet, they might be misconfigured, and they're exactly what you'd miss by relying on a 15-day-old enumeration.

# Recon refresh: enumerate, diff, probe the new ones
subfinder -d target.example.com -silent -o subs-refresh.txt

# What's new?
comm -23 \
  <(sort subs-refresh.txt) \
  <(sort subs-all.txt) > subs-new.txt

# What disappeared?
comm -13 \
  <(sort subs-refresh.txt) \
  <(sort subs-all.txt) > subs-removed.txt

# Probe new hosts
~/go/bin/httpx -l subs-new.txt -status-code -title -tech-detect -o new-hosts-live.txt

Tonight's numbers after running against all wildcard domains and named assets:

300+
Baseline Subdomains
7
New Subdomains
13
Dropped Subdomains
1,700+
New Historical URLs

Seven new hosts. Thirteen gone. And 1,700+ historical URLs surfaced from gau (GetAllUrls), which mines Wayback Machine, Common Crawl, and other passive sources. The historical URLs are often more interesting than the current ones — old endpoints that still resolve, deprecated parameter names that hint at API versioning, forgotten admin routes that show up in Wayback but not in any current docs.

Mine the past before you probe the present

Historical URL miners like gau and waybackurls surface endpoints that might have been removed from current documentation but still function on the backend. A deprecated API version that's technically "sunsetted" often isn't actually turned off. Pair the historical list with your live probe results: if a 2023 Wayback URL still returns 200 today, it's worth investigating why.

The Staging Platform

Of the seven new subdomains, most were either Cloudflare-blocked (403) or offline. One was a 302-to-live Render-hosted API reference. One was a Docusaurus documentation site. And one was this: a fully functional staging trading platform running Next.js, with no Cloudflare Access gate, no HTTP basic auth wall, nothing — just a live /login and /signup returning 200.

This is the classic staging misconfiguration. The platform's production environment sits behind proper WAF rules and authentication flows. The staging environment was apparently deployed without the same access controls. The result: a complete replica of the trading UI, publicly accessible to anyone who discovers the hostname.

$ ~/go/bin/httpx -u staging-[REDACTED].example.com -status-code -title -tech-detect
staging-[REDACTED].example.com [200] [Trading Platform - Staging] [Next.js][React][Vercel]

$ curl -I https://staging-[REDACTED].example.com/login
HTTP/2 200
# No authentication challenge. No access denial. Just: here's your login page.

Interesting details: the staging platform's login flow redirects to the production OAuth provider. That raises a question I can't answer from the outside: does the staging app register as a separate OAuth client with its own app_id, or does it share production credentials? If it shares production OAuth, then a staging IDOR might have production-level impact. If it's isolated, staging issues stay in staging.

That question gets answered when there are test accounts. Which is still the blocking dependency on this engagement. The staging platform is now mapped, documented, and flagged as a priority target. It goes nowhere without credentials.

Staging environments are production-risk until proven otherwise

The default assumption for any staging environment that shares OAuth, API keys, or database connections with production is that it carries production-level risk. Don't dismiss staging findings as "just staging" until you've verified the isolation boundary. If staging auth flows back to the production identity provider, a staging IDOR can affect real accounts.

The Docusaurus Trap

One of the new hosts looked exciting on first probe: 200 status, Docusaurus tech fingerprint, and a sitemap that listed pages named /api-explorer, /auth, /callback, /dashboard, and /endpoint. My pulse went up slightly.

Then I hit the pages.

$ for page in api-explorer auth callback dashboard endpoint; do
    curl -s -o /dev/null -w "%{http_code} $page\n" \
      https://legacy-api.[REDACTED].example.com/$page
  done

200 api-explorer
200 auth
200 callback
200 dashboard
200 endpoint

All 200s. Seemed promising. Until I read the content. Every single page was Docusaurus documentation: markdown-rendered descriptions of API endpoints, with example request/response pairs and parameter tables. The routes /auth and /callback were pages documenting the auth and callback flows — not live auth endpoints.

The sitemap was the tell I missed on first glance. Docusaurus generates sitemaps that include every documentation page. A page called /callback in a sitemap might be an OAuth callback route, or it might be the documentation page titled "Callback Reference." I assumed the former. It was the latter.

200 status + interesting route name ≠ live endpoint

Docusaurus, Gitbook, and similar docs platforms will name their pages to match the thing they're documenting. A doc site for an OAuth library will have pages called /auth, /callback, and /token. All returning 200. None of them are live auth endpoints. Read the response body before building a hypothesis around the URL. Content-type and first 100 bytes tells you whether you're looking at an API response or a rendered React doc page.

What the OAuth Config Told Me

Inside the documentation site, the OIDC discovery configuration was documented in full: the authorization server, token endpoint, supported grant types, and supported response types. One detail worth noting: the implicit flow was listed as supported.

The implicit flow is a legacy OAuth pattern that was deprecated in OAuth 2.1 and is generally considered less secure than the authorization code + PKCE flow. Programs that still have it enabled haven't necessarily been exploited — but the presence of an older, less-secure flow in the OIDC configuration is worth examining in the context of whether the OAuth implementation enforces stricter flows for production clients.

This is intelligence, not a finding. The doc page says "implicit flow is supported." That tells me to go look at the actual OAuth implementation and test whether production clients can be coerced into using it, whether there's a token leakage vector, or whether the implicit flow is just listed in the discovery document and never actually used. All of that requires authenticated testing and proxy observation of real OAuth flows.

# What I'm looking for in the next authenticated session:
# 1. Does any production client use response_type=token (implicit)?
# 2. Can you force response_type=token on a client configured for code flow?
# 3. Where does the implicit flow token end up (fragment, URL, logs)?
# 4. Is there a redirect_uri validation that's weaker on implicit flows?

These are hypotheses. Not findings. The methodology demands that I test each one before I write anything up.

The Recon Refresh Deliverable

Thirteen minutes, 60 tool calls. The session closed with updated engagement files, a refreshed subdomain list, three categories of new attack surface mapped and prioritized, and a threat model update reflecting the staging platform as a new top-3 target.

What the session did not produce: a single report-ready finding. That's correct. Recon produces intelligence. Testing produces findings. The staging platform is the most interesting thing in the session, and it goes precisely nowhere without test account credentials.

This is the recurring theme of this engagement. The map is good. The map keeps getting better. But a good map of a territory you can't enter is just a nice-looking document.

The diff is worth running even when you think nothing changed

15 days felt recent enough that I half-expected to find nothing new. Instead: 7 new subdomains, one of them a staging platform with no access controls. The programs with the most active development cycles — fintech, real-time trading, anything with frequent deploys — are the ones where staleness matters most. The faster the team moves, the faster the attack surface changes. Schedule the refresh before it becomes obviously stale.

What's Next

The priority hasn't changed. Everything points at the same gate: test accounts. The staging platform is a compelling new target, but only with credentials. The WebSocket API IDOR hypothesis from the threat model is compelling, but only with two accounts. The OAuth implicit flow question is worth investigating, but only with a real session to observe.

Two weeks. Fifteen-plus sessions. The map is more detailed than it's ever been. The moment we open the front door, there's a lot to test.