← back to lessons

Lesson: Firebase Hosting dangling-domain takeover fingerprint + passive/active confirmation boundary

Banked 2026-06-12 (Web2 gaming lane, Playtika H1 program, dev.gdpr.seriously.com).

The fingerprint (how to recognize it passively)

A subdomain is a Firebase Hosting dangling-domain takeover candidate when ALL hold: 1. dig A <host> resolves to Firebase Hosting anycast IPs: 151.101.1.195 and/or 151.101.65.195 (Fastly-fronted, shared by Firebase Hosting). A direct A-record to these, OR a CNAME to a Firebase target, both qualify. 2. GET https://<host>/ returns HTTP 404 with body <title>Site Not Found</title> whose body links to https://firebase.google.com/docs/hosting/ and shows the Firebase logo. That EXACT page = Firebase serving a request for a custom domain that NO project currently claims. 3. Sanity: a claimed Firebase site returns real app content or a custom 404, NOT this generic page. So the generic page == unclaimed == candidate.

Note these IPs are also generic Fastly. Disambiguate by the BODY: the "Site Not Found" page that links firebase.google.com is Firebase-specific. A plain Fastly "unknown domain" page is different wording. Always read the body, do not classify on IP alone.

The honest severity boundary (do NOT overclaim)

Passive evidence proves "DNS points at Firebase + no site claims it." It does NOT prove takeover is achievable. Modern Firebase custom-domain onboarding requires the claimer to pass an ownership-verification challenge (TXT / specific A-record). Whether the existing DNS satisfies that challenge is target-specific and only determinable by ATTEMPTING the claim in your own Firebase project - which is ACTIVE and out of passive-only ROE.

Therefore the correct passive verdict is: "Low/Medium UNCONFIRMED dangling-Firebase candidate, STAGED for an active claim-attempt verification." Never write "confirmed subdomain takeover" from passive signal alone. This mirrors the banked rule: VULNERABLE-CONFIRMED-direct != EXPLOIT-VIABLE-via-cascade - here, dangling-DNS-confirmed != takeover-viable. Empirically test (the claim attempt) before asserting.

Procedure to confirm (active, needs operator authorization)

In a throwaway Firebase project: Hosting -> Add custom domain -> enter the host. If Firebase accepts/provisions without demanding an un-settable TXT -> CONFIRMED takeover (Medium, submit). If it demands a TXT the attacker cannot set on the victim zone -> downgrade to informational stale-DNS-hygiene note.

Generalization (other providers, same logic)

The "fronting-IP/CNAME present + provider 'not found' page + no claiming tenant" pattern applies to Firebase, GitHub Pages ("There isn't a GitHub Pages site here"), Netlify, Surge, Fastly, S3 ("NoSuchBucket"), Azure, Heroku, etc. For EACH: passive = candidate; the takeover-viability depends on whether the provider lets you claim the name without a verification you cannot satisfy. Always stage, always confirm the claim step before submission. Read the body wording to identify the provider, never guess from IP.

Process lesson (certspotter noise)

certspotter issuances?include_subdomains=true returns multi-SAN co-tenant noise (unrelated domains sharing a certificate). ALWAYS apply a strict apex-suffix grep filter to the in-scope brand list before treating results as the target's attack surface. Raw certspotter output overstated the host count ~5x here (726 raw -> 156 genuine after suffix filter).

Generated 2026-07-02 13:15:05 UTC | auto-sync /15min