Every subdomain takeover writeup ends the same way: "an attacker could host a phishing page under your trusted domain."
That is the low-severity version.
In 2020, a researcher discovered four Acronis subdomains pointing to unclaimed Marketo endpoints and found something more serious buried in the HTTP response headers of a completely different endpoint. The subdomain takeover was not the vulnerability. It was the key that unlocked one.
The Setup: Four Dangling CNAMEs
@ashmek ran subdomain enumeration against acronis.com and found four marketing subdomains all pointing to Marketo landing page infrastructure:
register.acronis.com → acronis.mktoweb.com
promo.acronis.com → acronis.mktoweb.com
promosandbox.acronis.com → acronissandbox2.mktoweb.com
info.acronis.com → mkto-h0084.com
Each target returned 404. Each target was unclaimed. @ashmek confirmed with Marketo support that none of the listed domains were in use or configured anymore.
Standard subdomain takeover. Standard remediation: remove the CNAME records or reclaim the Marketo workspaces. At this point, severity is medium — phishing, content injection, brand impersonation.
Then they looked at the API response headers.
The Escalation: CORS With Credentials
While examining the Acronis account API at account.acronis.com, @ashmek intercepted a request and found this in the response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://register.acronis.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Accept, Authorization, Content-Type, ...
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: https://register.acronis.com with Access-Control-Allow-Credentials: true.
register.acronis.com is one of the four dangling subdomains. The one that is unclaimed on Marketo. The one any attacker can register right now.
The attack chain is now:
1. Attacker registers register.acronis.com on Marketo (free)
2. Attacker hosts malicious JavaScript on register.acronis.com
3. Victim visits register.acronis.com while logged into account.acronis.com
4. JavaScript calls account.acronis.com/v2/account with credentials
5. Browser sends the authenticated request — CORS policy allows it
6. account.acronis.com responds with the victim's account data
7. JavaScript reads the response — CORS + credentials = full access
8. Attacker exfiltrates account data, tokens, or session information
This is not phishing. The user does not need to enter their password on a fake form. They need only visit a subdomain that Acronis's own CORS policy trusts — a subdomain that anyone can claim.
Why this CORS Configuration is Dangerous
The browser's CORS model has one rule that matters here: when Access-Control-Allow-Credentials: true is set, the browser will include cookies and authorization headers in the cross-origin request. The response is readable by the requesting JavaScript.
This is explicitly why the spec prohibits Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true — the combination would allow any site to make authenticated API calls on behalf of the visitor. Browsers reject it.
But Access-Control-Allow-Origin: https://register.acronis.com is not a wildcard. It is a specific trusted origin. The browser allows it. The credentials are included. The response is readable.
The security assumption embedded in that CORS policy is: we control register.acronis.com. When that assumption is false — when the subdomain is unclaimed — the CORS policy has granted an arbitrary attacker the same cross-origin access that Acronis's own first-party applications have.
The Compound Vulnerability
Neither issue alone reaches this severity:
- Dangling CNAME alone: medium — phishing, content injection
- CORS with credentials alone: informative — only exploitable from a trusted origin
- Together: high — authenticated cross-origin API access from an attacker-controlled page
This is the compound chain that individual controls miss. CTL.DNS.DANGLING.001 fires on the dangling CNAME. A CORS policy check fires on the Allow-Credentials: true configuration. Neither control alone captures the full attack path — only the combination does.
In Stave's compound chain model:
chain: subdomain_cors_credential_theft
members:
- CTL.DNS.DANGLING.001 # CNAME points to unclaimed endpoint
- CTL.CORS.CREDENTIALS.001 # Allow-Credentials: true with dynamic origin
preconditions: [internet_access]
postconditions: [credential_access]
narrative: >
A dangling CNAME on a subdomain that is explicitly trusted
by a CORS policy with Allow-Credentials: true enables an
attacker who claims the subdomain to make authenticated
cross-origin API calls on behalf of any victim who visits
the attacker-controlled page while logged in.
The chain fires when both controls fail simultaneously on related assets. One control finding remediated — either remove the dangling CNAME or remove Allow-Credentials: true — breaks the chain.
The Wildcard CORS Pattern
The Acronis case used an explicit origin (register.acronis.com), but the more common and more dangerous pattern is a wildcard subdomain CORS policy:
# Dangerous: any subdomain is trusted
Access-Control-Allow-Origin: https://anything.acronis.com
Access-Control-Allow-Credentials: true
When an API reflects the Origin header back as Access-Control-Allow-Origin without validation — a common misconfiguration — any subdomain the attacker controls becomes a trusted CORS origin. Combined with Allow-Credentials: true, any subdomain takeover on any *.acronis.com host unlocks authenticated API access.
The correct configuration trusts only the specific origins that legitimately need cross-origin access:
# Safe: explicit allowlist of known first-party origins
Access-Control-Allow-Origin: https://console.acronis.com
Access-Control-Allow-Credentials: true
Or, if credentials are not required:
# Safe: wildcard only when credentials are not needed
Access-Control-Allow-Origin: *
# Access-Control-Allow-Credentials omitted (defaults to false)
What Stave Detects
Running the Acronis scenario through Stave:
CTL.DNS.DANGLING.001 CRITICAL initial_access
"DNS CNAME Must Not Point to Unclaimed Third-Party Service"
fires on: register.acronis.com → acronis.mktoweb.com (404, unclaimed)
fires on: promo.acronis.com, promosandbox.acronis.com, info.acronis.com
CTL.CORS.CREDENTIALS.001 HIGH credential_access
"API Endpoints Must Not Allow Credentials from Untrusted Origins"
fires on: account.acronis.com returning Allow-Credentials: true
for an origin not in the explicit safe list
The compound chain subdomain_cors_credential_theft fires because both controls fail on related assets — the dangling subdomains and the CORS policy reference the same domain namespace.
Neither control alone justifies the chain's severity. Together, they describe a path from "attacker registers a free Marketo account" to "attacker reads authenticated account data for any victim who visits the page."
The Infrastructure Invariants
Two System Invariants were false simultaneously:
Invariant 1: Every DNS CNAME record must point to a target owned by the same organization.
register.acronis.com → acronis.mktoweb.com where acronis.mktoweb.com was unclaimed. False.
Invariant 2: API endpoints that set Access-Control-Allow-Credentials: true must only trust origins that are verified to be owned by the same organization.
account.acronis.com trusted register.acronis.com. The trust was not verified against actual ownership. False.
When both are false at the same time, on overlapping domain namespaces, the compound attack path opens.
Remediation
For the dangling CNAMEs — remove them or reclaim the Marketo workspaces. Five minutes per subdomain.
For the CORS policy — audit every endpoint that returns Access-Control-Allow-Credentials: true and verify that every origin in the allowlist is actively owned and monitored.
# Find all responses with Allow-Credentials from your API
# (run against your own API in a security review context)
curl -s -I -H "Origin: https://register.example.com" \
https://api.example.com/v2/account | \
grep -i "access-control"
If Access-Control-Allow-Origin reflects back an origin from *.yourcompany.com, check every subdomain in that namespace for dangling CNAMEs. Any unclaimed subdomain that matches the CORS reflection pattern is exploitable.
Checklist
- All DNS CNAMEs point to targets owned and actively maintained by the organization
-
Access-Control-Allow-Credentials: trueendpoints have an explicit, audited origin allowlist - No CORS policy reflects
Originheader directly without validation - Subdomain enumeration run against all domains in the CORS allowlist
-
CTL.DNS.DANGLING.001andCTL.CORS.CREDENTIALS.001run together in CI - Deprovisioning process removes DNS records before canceling third-party service accounts
The subdomain takeover gave the attacker a trusted origin. The CORS policy gave that origin authenticated API access. Neither was the vulnerability alone. Together they were.
Based on the publicly disclosed Acronis subdomain takeover report on HackerOne. The compound chain analysis — dangling CNAME × CORS credentials — is detected by Stave, an open-source infrastructure invariant engine that evaluates configuration snapshots without cloud credentials.
Top comments (0)