Banked: 2026-06-12 (WEB2 passive devtools lane, target: Doppler HackerOne) Class: Web2 / CORS false-positive elimination
api.doppler.com/v3/me returns Access-Control-Allow-Origin: https://docs.doppler.com together with Access-Control-Allow-Credentials: true. At first glance this is the classic "credentialed CORS" red flag and tempting to stage. It is INERT. Two independent gates kill it; checking only one is the amateur error.
Send the request with MULTIPLE attacker-controlled Origins and compare:
- Origin: https://evil.com
- Origin: https://docs.doppler.com.evil.com (suffix-confusion)
- Origin: https://evildoppler.com (prefix-confusion)
- Origin: null
- the legit Origin: https://docs.doppler.com
If ACAO returns the SAME fixed value (here https://docs.doppler.com) for EVERY origin, the server is using a hardcoded static allowlist - it is NOT echoing the request Origin. An attacker page cannot make its browser Origin equal docs.doppler.com, so no cross-site credentialed read is possible. EXPLOITABLE only if the value CHANGES to reflect (echo) the attacker origin, or matches a permissive regex (suffix/prefix/null bypass). One single-origin probe cannot distinguish static from reflective - you MUST send >=3 varied origins.
Even a reflective ACAO+creds is harmless if the API authenticates by bearer token (Authorization header) rather than ambient session cookie. Browsers do not auto-attach Authorization headers cross-site; withCredentials only ships cookies/TLS-client-certs. Confirm the model: a 401 that sets only an infra cookie (_cfuvid, Cloudflare) and NO app session cookie => bearer-token API => credentialed-CORS yields nothing even if reflective. Doppler's API is bearer-token, so this is a second, independent kill.
Before staging ANY credentialed-CORS finding: 1. Replay with >=3 distinct attacker origins (evil / suffix / prefix / null). Reflective or regex-permissive = candidate; identical-static = DEAD. 2. Determine auth model. Bearer-Authorization API + cookieless session = DEAD regardless of Gate 1. Stage ONLY if BOTH gates fail (reflective/permissive ACAO AND cookie-borne session auth).
Extends the banked CF-Access / DataDome CORS-reflection FP rules (MEMORY): those covered WAF wrappers reflecting Origin. This adds the static-allowlist case (looks reflective on a single probe, isn't) and formalizes the bearer-vs-cookie auth-model gate as the second independent check. Same parent class: "credentialed CORS header present != exploitable."