[{"data":1,"prerenderedAt":349},["ShallowReactive",2],{"blog-diagrams/csrf-who-attaches-the-cookie":3},{"id":4,"title":5,"body":6,"category":322,"date":323,"dateModified":323,"description":324,"draft":325,"extension":326,"faq":327,"featured":325,"headerVariant":332,"image":333,"keywords":335,"meta":336,"navigation":148,"ogDescription":337,"ogTitle":338,"path":339,"readTime":340,"schemaOrg":341,"schemaType":342,"seo":343,"sitemap":344,"stem":345,"tags":346,"twitterCard":347,"__hash__":348},"blog/blog/diagrams/csrf-who-attaches-the-cookie.md","CSRF: Who Actually Attaches the Cookie (Diagram)",{"type":7,"value":8,"toc":316},"minimark",[9,13,16,24,29,32,35,38,41,51,55,58,88,95,99,102,252,281,300,312],[10,11,12],"p",{},"The confusing thing about CSRF is not what the attacker does. It's why your server believes them.",[10,14,15],{},"Nothing gets stolen. The attacker never sees the session cookie, never cracks anything, and never touches your infrastructure. They just get the victim's browser to make a request, and the browser helpfully attaches the credential on their behalf.",[17,18],"diagram",{"alt":19,"caption":20,"height":21,"src":22,"width":23},"A sequence diagram. The victim logs into your app and receives a session cookie. They then open a page on an attacker site, which returns a hidden self-submitting form. The browser sends that POST to your app and attaches the session cookie automatically, so the server sees a valid request.","Nobody steals the cookie. The browser attaches it for them.",1172,"csrf-who-attaches-the-cookie",1568,[25,26,28],"h2",{"id":27},"reading-the-diagram","Reading the diagram",[10,30,31],{},"The green band is an ordinary login. Your app sets a session cookie, which is what it's supposed to do.",[10,33,34],{},"The amber band is the setup, and notice it never touches your server's column. The only thing the victim does wrong is open a link, and that barely qualifies. The attacker's page hands their browser a form that submits itself, aimed at your domain.",[10,36,37],{},"The red band is the whole attack. The browser sends that POST to your app and, because the request is going to your domain, it attaches your session cookie. It does this automatically. It's not a bug, it's what cookies have always done.",[10,39,40],{},"Your server has now received a request carrying a valid session, with no way to tell it apart from a real one.",[42,43,44],"warning-box",{},[10,45,46,50],{},[47,48,49],"strong",{},"This is why the usual defences do nothing here."," Rotating secrets, longer passwords, encrypting the database, HTTPS: none of them touch this. The request is legitimate in every way your server can measure. The only thing wrong with it is that the user did not intend it.",[25,52,54],{"id":53},"what-actually-stops-it","What actually stops it",[10,56,57],{},"Because the problem is intent rather than identity, the fix has to prove the request came from your own interface.",[59,60,61,76,82],"ul",{},[62,63,64,71,72,75],"li",{},[47,65,66,70],{},[67,68,69],"code",{},"SameSite"," cookies."," ",[67,73,74],{},"Lax"," is the modern browser default and blocks the cross-site POST in the diagram outright. This is most of your protection and you may already have it for free.",[62,77,78,81],{},[47,79,80],{},"CSRF tokens."," A per-session random value your page includes and the attacker's page cannot read. Worth adding on anything that moves money or deletes data.",[62,83,84,87],{},[47,85,86],{},"Re-authenticate for the serious things."," Asking for a password before deleting an account defeats this regardless of cookies.",[10,89,90,91,94],{},"What does not work is checking the ",[67,92,93],{},"Referer"," header alone, which is stripped or spoofed often enough to be unreliable.",[25,96,98],{"id":97},"the-mermaid-source","The Mermaid source",[10,100,101],{},"Copy this and adapt it to your own endpoints.",[103,104,109],"pre",{"className":105,"code":106,"language":107,"meta":108,"style":108},"language-mermaid shiki shiki-themes github-dark","sequenceDiagram\n    autonumber\n    participant V as Victim's browser\n    participant E as evil-site.com\u003Cbr/>(the attacker)\n    participant Y as your-app.com\u003Cbr/>(yours)\n\n    rect rgb(236, 253, 245)\n        V->>Y: logs in normally\n        Y-->>V: sets session cookie\n    end\n\n    Note over V,Y: nothing is wrong yet\n\n    rect rgb(255, 251, 235)\n        V->>E: victim opens a link in another tab\n        E-->>V: a page with a hidden form that\u003Cbr/>submits itself to your-app.com\n    end\n\n    rect rgb(254, 242, 242)\n        V->>Y: POST /account/delete\n        Y-->>V: valid cookie, so the request runs\n    end\n\n    Note over V,Y: the browser attached the session cookie by itself.\u003Cbr/>nobody had to steal anything.\n","mermaid","",[67,110,111,119,125,131,137,143,150,156,162,168,174,179,185,190,196,202,208,213,218,224,230,236,241,246],{"__ignoreMap":108},[112,113,116],"span",{"class":114,"line":115},"line",1,[112,117,118],{},"sequenceDiagram\n",[112,120,122],{"class":114,"line":121},2,[112,123,124],{},"    autonumber\n",[112,126,128],{"class":114,"line":127},3,[112,129,130],{},"    participant V as Victim's browser\n",[112,132,134],{"class":114,"line":133},4,[112,135,136],{},"    participant E as evil-site.com\u003Cbr/>(the attacker)\n",[112,138,140],{"class":114,"line":139},5,[112,141,142],{},"    participant Y as your-app.com\u003Cbr/>(yours)\n",[112,144,146],{"class":114,"line":145},6,[112,147,149],{"emptyLinePlaceholder":148},true,"\n",[112,151,153],{"class":114,"line":152},7,[112,154,155],{},"    rect rgb(236, 253, 245)\n",[112,157,159],{"class":114,"line":158},8,[112,160,161],{},"        V->>Y: logs in normally\n",[112,163,165],{"class":114,"line":164},9,[112,166,167],{},"        Y-->>V: sets session cookie\n",[112,169,171],{"class":114,"line":170},10,[112,172,173],{},"    end\n",[112,175,177],{"class":114,"line":176},11,[112,178,149],{"emptyLinePlaceholder":148},[112,180,182],{"class":114,"line":181},12,[112,183,184],{},"    Note over V,Y: nothing is wrong yet\n",[112,186,188],{"class":114,"line":187},13,[112,189,149],{"emptyLinePlaceholder":148},[112,191,193],{"class":114,"line":192},14,[112,194,195],{},"    rect rgb(255, 251, 235)\n",[112,197,199],{"class":114,"line":198},15,[112,200,201],{},"        V->>E: victim opens a link in another tab\n",[112,203,205],{"class":114,"line":204},16,[112,206,207],{},"        E-->>V: a page with a hidden form that\u003Cbr/>submits itself to your-app.com\n",[112,209,211],{"class":114,"line":210},17,[112,212,173],{},[112,214,216],{"class":114,"line":215},18,[112,217,149],{"emptyLinePlaceholder":148},[112,219,221],{"class":114,"line":220},19,[112,222,223],{},"    rect rgb(254, 242, 242)\n",[112,225,227],{"class":114,"line":226},20,[112,228,229],{},"        V->>Y: POST /account/delete\n",[112,231,233],{"class":114,"line":232},21,[112,234,235],{},"        Y-->>V: valid cookie, so the request runs\n",[112,237,239],{"class":114,"line":238},22,[112,240,173],{},[112,242,244],{"class":114,"line":243},23,[112,245,149],{"emptyLinePlaceholder":148},[112,247,249],{"class":114,"line":248},24,[112,250,251],{},"    Note over V,Y: the browser attached the session cookie by itself.\u003Cbr/>nobody had to steal anything.\n",[253,254,255,262,268],"faq-section",{},[256,257,259],"faq-item",{"question":258},"How does the attacker get my session cookie?",[10,260,261],{},"They do not. That is the part people miss. The attacker never sees or touches the cookie. They only need the victim's browser to send a request to your domain, and the browser attaches the cookie to that request by itself, because that is what cookies are for. This is why stronger passwords, rotating secrets and better encryption do nothing against CSRF.",[256,263,265],{"question":264},"Does HTTPS protect against CSRF?",[10,266,267],{},"No. HTTPS stops someone reading the traffic in transit. In a CSRF attack nobody is reading traffic. The request is well formed, correctly encrypted, and carries a genuine session, which is exactly why the server accepts it.",[256,269,271],{"question":270},"Is SameSite enough on its own?",[10,272,273,276,277,280],{},[67,274,275],{},"SameSite=Lax"," is the default in modern browsers and it blocks the common cross-site POST, so it stops most of this. It is not a complete answer: older browsers, deliberately relaxed ",[67,278,279],{},"SameSite=None"," cookies, and some same-site subdomain setups still leave a gap. Add CSRF tokens on anything that moves money or deletes data.",[282,283,284,290,295],"related-articles",{},[285,286],"related-card",{"description":287,"href":288,"title":289},"The complete guide, including framework-specific protection","/blog/vulnerabilities/csrf","CSRF Explained in Full",[285,291],{"description":292,"href":293,"title":294},"Why a request arriving at your server cannot be trusted on its face","/blog/diagrams/vibe-coded-trust-boundary","Where the Trust Boundary Sits",[285,296],{"description":297,"href":298,"title":299},"Cookie flags, rotation, and timeouts","/blog/how-to/session-management","How to Handle Sessions Safely",[301,302,305,309],"cta-box",{"href":303,"label":304},"/","Start Free Scan",[25,306,308],{"id":307},"are-your-cookies-set-correctly","Are your cookies set correctly?",[10,310,311],{},"A scan checks your cookie flags, including SameSite, on every response.",[313,314,315],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":108,"searchDepth":121,"depth":121,"links":317},[318,319,320,321],{"id":27,"depth":121,"text":28},{"id":53,"depth":121,"text":54},{"id":97,"depth":121,"text":98},{"id":307,"depth":121,"text":308},"diagrams","2026-07-31","A sequence diagram of a CSRF attack, showing the step everyone misses: the victim's own browser attaches the session cookie, so nothing has to be stolen.",false,"md",[328,329,330],{"question":258,"answer":261},{"question":264,"answer":267},{"question":270,"answer":331},"SameSite=Lax is the default in modern browsers and it blocks the common cross-site POST, so it stops most of this. It is not a complete answer: older browsers, deliberately relaxed SameSite=None cookies, and some same-site subdomain setups still leave a gap. Add CSRF tokens on anything that moves money or deletes data.","blue",{"src":334,"alt":19},"https://checkyourvibe.dev/diagrams/csrf-who-attaches-the-cookie.png","csrf diagram, how csrf works, cross site request forgery explained, csrf session cookie, why does my server accept the request",{"ogImage":334},"Nobody steals the cookie in a CSRF attack. The browser attaches it for them.",null,"/blog/diagrams/csrf-who-attaches-the-cookie","4 min read","[object Object]","Article",{"title":5,"description":324},{"loc":339},"blog/diagrams/csrf-who-attaches-the-cookie",[],"summary_large_image","ogwC3ta2GCPenm_wtoCWCuWEHy3qUfeytHqLM93atDc",1785543175821]