DEV Community

Bala Paranj
Bala Paranj

Posted on

Subdomain Takeover is Not Just Phishing: How Acronis Nearly Lost Authenticated API Access

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.comacronis.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"
Enter fullscreen mode Exit fullscreen mode

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: true endpoints have an explicit, audited origin allowlist
  • No CORS policy reflects Origin header directly without validation
  • Subdomain enumeration run against all domains in the CORS allowlist
  • CTL.DNS.DANGLING.001 and CTL.CORS.CREDENTIALS.001 run 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)