← Return to Ledger
MODULE_10 // CROSS-ORIGIN TRUST ABUSE & AUTH FLUX

CSRF & Authentication Bugs

OPERATIONAL OBJECTIVE

Two attack classes, one theme: breaking the gate. CSRF exploits the browser's automatic trust — it sends cookies whether you want it to or not. Authentication bugs exploit the gate itself — weak login flows, predictable tokens, no rate limits, MFA that can be skipped. Together they account for a massive slice of paid bug bounty reports.

Part 1 — Cross-Site Request Forgery (CSRF)

CSRF is an attack that tricks an authenticated user's browser into sending an HTTP request they didn't intend to make. The server receives the request with the victim's valid session cookie attached — and has no way to distinguish it from a legitimate action.

The core mechanic: browsers attach cookies to every request for a domain, regardless of where the request originates. A page on evil.com can force a request to bank.com, and the victim's browser dutifully sends the session cookie along with it.

🔍 Why this works CSRF doesn't inject anything. It doesn't need XSS. It just needs the victim's browser to make a request it never consented to — relying entirely on the browser's default cookie behavior. The server sees valid credentials from what looks like a legitimate client.

Attack Vector 1 — GET-Based State Changes

The most dangerous pattern: a web app uses GET requests to perform actions that change data. Any HTML tag that fetches a URL can trigger it silently.

Attacker's page — victim loads this while logged into bank.com<!-- Option A: image tag — zero interaction needed -->
<img src="https://bank.com/transfer?to=attacker&amount=5000">

<!-- Option B: invisible iframe -->
<iframe src="https://bank.com/transfer?to=attacker&amount=5000" style="display:none"></iframe>

<!-- Option C: link the victim clicks -->
<a href="https://bank.com/delete-account">Click for free gift</a>

Attack Vector 2 — POST-Based CSRF

Most sensitive actions use POST. Slightly more setup required — but a hidden form that auto-submits on page load is all it takes.

Auto-submitting CSRF PoC — the victim just has to visit this page<html>
<body onload="document.forms[0].submit()">
  <form action="https://bank.com/transfer" method="POST">
    <input type="hidden" name="to"     value="attacker_account">
    <input type="hidden" name="amount" value="10000">
  </form>
</body>
</html>
⚠️ Burp Suite shortcut Right-click any request in Burp → Engagement Tools → Generate CSRF PoC. It builds the auto-submit form for you. Change the parameter values, host the file, send the link to your test account.

How the Full Attack Flows

Actor
Step
Victim
Logs into bank.com — session cookie set in browser Normal login
Attacker
Sends victim a link to evil.com (phishing, DM, forum post) Social engineering
Victim
Opens evil.com — page auto-submits hidden form to bank.com One page load
Browser
POST /transfer to bank.com — attaches session cookie automatically Browser default behavior
Bank Server
Sees valid session + valid POST params → executes transfer Cannot distinguish
Attacker
$10,000 received. Victim never knew. Attack complete

CSRF Defenses — And Every Way They Break

Anti-CSRF Tokens

The server embeds a secret, unpredictable token in every form. On submission it checks the token matches. An attacker can't read it cross-origin (Same-Origin Policy), so they can't include it in the forged request.

Properly protected form<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="a3f8e2c1d9b746f...">
  <input name="amount" value="100">
</form>

In theory, airtight. In practice — full of holes. Here's the bypass catalogue:

Token Not Validated Server-Side
Token exists in the form, but the server never checks it on submission. Deleting the token parameter entirely from the request — the action still succeeds. Extremely common. Developers add the frontend token but skip the backend check.
Method Switch Bypass
App validates CSRF token on POST but not on GET. Change the method: POST → GET. Many frameworks don't re-validate on method change. If the endpoint accepts both methods, no token needed.
Token Tied to User, Not Session
Token is per-user but static across sessions. Capture your own token, use it in the forged request against the same user after they log in again. Or share the token between tabs/sessions — it still works.
Content-Type Bypass
Some apps only validate CSRF tokens when Content-Type: application/x-www-form-urlencoded. Switching to text/plain or application/json bypasses the check if the endpoint accepts multiple content types.
Double Submit Cookie Forgery
Pattern: CSRF token set as a cookie AND a form field — server compares them. If attacker can set cookies (via subdomain XSS or cookie tossing), they control both values. They match. Defense bypassed.
Token in URL / Referer Leak
If CSRF token appears in the URL (?csrf=TOKEN), it leaks in Referer headers to any third-party resource on the page (analytics, CDNs). Attacker reads it from server logs.

SameSite Cookie Attribute

Browsers added SameSite to address CSRF at the transport level — controlling when cookies travel cross-site.

ValueBehaviorCSRF ProtectionBypass
Strict Cookie never sent on any cross-site request, including top-level link clicks from external sites Maximum Subdomain attacks only
Lax Cookie sent on top-level navigations (link clicks) but NOT on cross-site sub-resources (images, AJAX, iframes, forms) Strong GET-based state changes; legacy browser gaps
None; Secure Cookie sent on ALL cross-site requests — required for embedded iframes, OAuth, payment widgets None Classic CSRF works in full
(absent) Chrome defaults to Lax since 2020. Older browsers treat as None Partial Older browsers; GET-based actions
⚠️ SameSite=Lax Bypass — GET State Change Lax still allows cookies on GET top-level navigations (the user clicks a link). If the server accepts state-changing GET requests, a crafted link is enough. CSRF via GET works even with SameSite=Lax. This is why using GET for state changes is a bug on its own, regardless of CSRF token presence.

Referer / Origin Header Validation — Bypass Methods

⚡ Lab 1 — CSRF Attack Simulator

Toggle defenses and fire the forged request. Watch the server log. Each combination teaches a real attack scenario.

Defense Configuration
Attack Parameters
POST /api/transfer
Cookie: session=victim_token ✓
Origin: https://evil.com
Body: to=attacker&amount=10000
Server Log
[system] Bank API tracking active session... awaiting requests.

CSRF Against JSON APIs — The "JSON is Safe" Myth

Developers often assume REST APIs accepting application/json are immune to CSRF because HTML forms can't set a custom Content-Type. This is false in two ways:

Form-based CSRF against a JSON endpoint using text/plain enctype<form action="https://api.target.com/transfer"
      method="POST"
      enctype="text/plain">
  <!-- name becomes the JSON key, value becomes the rest -->
  <input name='{"to":"attacker","amount":1000,"padding":"'
         value='"}'>
</form>

<!-- Resulting body sent to server: -->
{"to":"attacker","amount":1000,"padding":"="}

If the server parses this as JSON while ignoring the trailing =, the attack works. Additionally — if the endpoint accepts application/x-www-form-urlencoded alongside JSON (common in loose frameworks), standard form CSRF works directly.

🏆 CSRF via XSS XSS completely neutralizes CSRF token defenses. JavaScript can: (1) fetch the page containing the token, (2) extract it from the DOM, (3) submit a forged POST with the valid token. Any XSS on the same origin defeats CSRF protection entirely. This is why defense-in-depth matters — you can't rely on CSRF tokens if XSS exists anywhere.

Part 2 — Authentication Bugs

Authentication bugs are weaknesses in the "who are you?" layer — the login mechanism, password reset flows, MFA implementation, and session lifecycle. Unlike CSRF (which abuses a working session), these bugs break the gate itself.

Username Enumeration

Applications inadvertently reveal which accounts exist through different responses to login attempts. Different error messages are the most obvious form — but timing side-channels are harder to spot and just as exploitable.

Enumeration MethodWhat LeaksHow to Test
Different error messages "Incorrect password" vs "Account not found" — text directly confirms valid accounts Try known-valid username vs random strings. Compare response body text.
Response timing Valid usernames trigger a password hash computation (slow). Invalid usernames return early (fast). Measurable latency difference even with identical error messages. Burp Intruder → Columns → Response Received. Sort by time. Valid accounts cluster at higher values.
Password reset page "Reset email sent to admin@..." vs "No account found" — confirms the address Submit reset for known accounts vs made-up ones. Compare responses.
Account registration "Username already taken" confirms the account exists Try registering common usernames: admin, root, support, api, test.
Response size difference Identical error text but different whitespace, field counts, or JSON keys Burp Intruder → Columns → Response Length. Different lengths = different responses.
🔍 Why enumeration matters beyond Low severity Username enumeration alone is often rated Low. Its value is as a prerequisite for higher-severity chains: credential stuffing (testing breach dump passwords against confirmed accounts), password spraying (one common password like Summer2024! across all confirmed usernames), and targeted phishing.
⚡ Lab 2 — Auth Enumeration & Rate Limit Simulator

Watch how different usernames produce different server responses — and how rate limiting (when present) shuts down brute-force. Toggle the rate limit and spam attempts to see both behaviors.

Login Request
Try these usernames
X-Forwarded-For Bypass

When Rate Limit is ON, rotate this value to bypass IP-based lockout.

Server Response
Waiting for request...
Attempt Counter
0 failed attempts this session

Brute Force & Rate Limit Bypasses

Even when rate limiting exists, implementation flaws commonly allow attackers to bypass it entirely.

X-Forwarded-For Rotation
App trusts X-Forwarded-For as the real client IP. Header is user-controlled. Rotate it on each request — each attempt appears to come from a different IP. No lockout ever triggers.

X-Forwarded-For: 1.1.1.1 → attempt 1
X-Forwarded-For: 1.1.1.2 → attempt 2
Counter Reset via Own Login
App locks account after N failures but resets the counter on any successful login. After 4 failed attempts on the target, authenticate as yourself — counter resets. Resume attacking. Infinitely scalable.

fail×4 → login as self → fail×4 → repeat
Burp Intruder — Pitchfork Mode
Two synchronized payload lists: usernames + passwords from breach dumps. Cycles them in parallel — tests credential pairs without the M×N explosion of Cluster Bomb. Best for credential stuffing at scale.
Password Spraying
One password, many accounts. Avoids per-account lockouts entirely. Use seasonal passwords: Summer2024!, Company123!. After enumerating valid usernames, try one guess per account per hour.

Password Reset Vulnerabilities

Reset flows are multi-step, complex, and written once — then forgotten. That combination breeds bugs.

Host Header Injection

Some frameworks build the password reset URL using the Host request header. An attacker intercepts the reset request and substitutes their own domain:

Normal Request POST /forgot-password
Host: target.com
body: email=victim@mail.com

→ Email sent:
https://target.com/reset?token=SECRET
Injected Request POST /forgot-password
Host: attacker.com
body: email=victim@mail.com

→ Email sent:
https://attacker.com/reset?token=SECRET

The victim receives an email pointing to attacker.com. When they click it, the reset token lands on the attacker's server. Use Burp Collaborator as the Host value to detect this — any DNS/HTTP ping to your Collaborator URL confirms the vulnerability.

Weak Token Entropy

Test method: Request resets for your own account at known times. Check if the token correlates to a timestamp or sequential value. Request multiple tokens in quick succession — if they're incrementing, the model is broken.

Token Lifecycle Flaws


Multi-Factor Authentication Bypasses

MFA bugs are among the highest-paying authentication findings. The assumption that "MFA = secure" makes them easy to overlook — and expensive when they're found.

⚡ Lab 3 — MFA Bypass Simulator

Select an attack vector and trace how MFA can be bypassed at each step of the authentication flow.

Select an attack to see how it works.

MFA Attack Vectors — Full Breakdown

Testing MFA skip — send this after credentials verify, before /mfa/verify# Step 1: POST /login with valid credentials
# Server sets: Set-Cookie: session=PARTIAL_TOKEN; Path=/

# Step 2: Skip POST /mfa/verify entirely
# Attempt: GET /dashboard with the partial token
GET /dashboard HTTP/1.1
Cookie: session=PARTIAL_TOKEN

# If 200 OK — MFA step is not enforced server-side
# If 302 /mfa — MFA correctly enforced

Session Management Post-Authentication

Authentication bugs don't end at login. The post-login session lifecycle has its own distinct vulnerability class.


Real Bug Bounty Findings

Representative findings from public HackerOne/Bugcrowd disclosures. Study the attack chain — this is what reports look like.

Critical — Full ATO
CSRF on Email Change → Account Takeover
No CSRF token + no SameSite on email-change endpoint. Attacker sends victim a page with an auto-submitting form changing victim's email to attacker's address. Attacker then requests a password reset — receives link. Full ATO.
~$3,500
Critical — MFA Bypass
Response Manipulation Bypasses MFA Entirely
Application validated MFA client-side using the API response body. Intercepting /mfa/verify response and changing "mfa_passed": false to true bypassed the second factor. Full account access with just a username and password.
~$7,500
Critical — Auth Bypass
Host Header Injection in Password Reset Email
Reset URL built from Host header. Attacker submits reset with Host: attacker.com. Victim receives email with link to attacker's server. Reset token captured. Password reset to attacker's choice. Detected with Burp Collaborator.
~$4,200
High — Unlimited Brute Force
Rate Limit Bypass via X-Forwarded-For
Login rate limit enforced by source IP. App trusted X-Forwarded-For header. Rotating the header value per request allowed unlimited attempts. Combined with username enumeration (different error messages) — full credential brute-force pipeline.
~$1,800
High — Auth Bypass
CSRF Token Present But Never Validated
Token existed in every form. Removing it entirely from the POST request — server accepted the action anyway. Backend generated the token client-side but had no validation logic on submission. Affected fund transfer and account deletion endpoints.
~$2,100
Medium — Session Persistence
Sessions Not Invalidated on Logout or Password Change
Session tokens remained valid server-side after both logout and password change. A token captured via earlier XSS continued to grant full access days after the victim "secured" their account by changing their password.
~$900

Testing Methodology — CSRF & Auth Bugs

CSRF Testing Checklist

1
Map all state-changing actions

Profile update, password change, email change, fund transfer, account deletion, permission grants, API key generation. Every action that modifies data is a CSRF candidate.

2
Check the request method

Is the action POST/PUT/DELETE — or GET? GET-based state changes are automatically higher severity. Test if changing POST to GET on an action still works.

3
Check cookie SameSite attribute

DevTools → Application → Cookies. Is SameSite present? If None or absent, cookies travel cross-site. CSRF is mechanically possible regardless of token status.

4
Test CSRF token validation

Remove the token entirely — does the request succeed? Change token to garbage — does it succeed? Try a valid token from a different session — does it succeed? Any "yes" is a bug.

5
Build and test the PoC

Burp → right-click request → Engagement Tools → Generate CSRF PoC. Modify parameter values. Open in browser while logged in as test account. Confirm action executes. Screenshot each step for the report.

Auth Bug Testing Checklist

1
Test for username enumeration

Try known-valid vs known-invalid usernames at login, password reset, and registration. Compare: response body text, status codes, response length, and response time.

2
Test rate limiting

Send 10+ failed login attempts. Does the server lock you out? If yes — try rotating X-Forwarded-For, X-Real-IP, CF-Connecting-IP headers on each attempt.

3
Probe the password reset flow

Request resets at known times (timestamp tokens). Request multiple in sequence (incrementing tokens). Check if old tokens still work after new ones are generated. Intercept with Burp Collaborator in the Host header.

4
Audit MFA implementation

Skip the /mfa/verify step. Intercept and modify the MFA response. Try OTP brute-force on test accounts. Test code reuse within 30-second windows. Check backup code endpoints for IDOR.

5
Test session invalidation

Log out — replay request with old cookie. Change password — replay with pre-change cookie. Both should reject. If either accepts, report it. Note session ID before and after login — if unchanged, session fixation.

Essential Tools for This Chapter

ToolPurposeKey Usage
Burp Suite Intercept, modify, replay all requests Right-click → Generate CSRF PoC. Intruder for brute-force. Collaborator for Host header detection.
Burp Intruder Automated credential testing Pitchfork mode for credential pairs. Cluster Bomb for small username×password matrices. Check Response Length column for enumeration.
DVWA Local CSRF and brute-force lab CSRF module at Low/Medium/High. Brute force module. Essential for building PoC skills before live targets.
Burp Collaborator Out-of-band detection Use as the Host header value in password reset requests. Any DNS/HTTP callback confirms Host header injection.
PortSwigger Labs Guided hands-on practice CSRF labs 1–8. Authentication labs including enumeration, brute-force, MFA bypass series.

Chapter 10 Operational Checklist

0 / 13
COMPLETE
PortSwigger Labs
Hands-On Drills
Knowledge Checks
Q1 — CSRF Mechanics

Explain in plain terms why the browser attaches cookies to cross-site requests. What specific browser behavior does CSRF exploit, and why can't the target server distinguish a forged request from a real one?

Q2 — CSRF Token Failure Modes

Name three scenarios where a CSRF token is present in the form but the protection still fails. For each, describe what the attacker does to bypass it.

Q3 — Enumeration to Exploit Chain

Username enumeration is typically a Low finding. Describe a full attack chain where enumeration is the first step leading to a Critical or High severity outcome. What additional conditions enable the escalation?

Q4 — Host Header Injection

Walk through the Host Header injection attack on a password reset endpoint step by step. What server-side condition makes this possible, and how would you detect it without the victim actually clicking the link?

Q5 — MFA Bypass Strategy

You're testing an app with MFA. The OTP endpoint has rate limiting. The response body can't be manipulated client-side. What other MFA bypass vectors would you test, and in what order?