Man In The Middle Samesite And The Rest Of The Injection Family

HTTPS quietly defeats most man-in-the-middle attacks by default. SameSite, site versus origin, and the rest of the injection family close out the gaps that HTTPS alone doesn't.

July 25, 20266 min read4 / 4

The last post covered a vulnerability that never touched the network at all, just a request payload the server trusted too much. This one is about the network itself, and the handful of remaining gaps that don't get their own chapter.

Man-in-the-Middle Sounds Scarier Than It Usually Is Now

A man-in-the-middle attack is exactly what it sounds like: someone sits between the browser and the server, reading or altering traffic as it passes through.

HTTPS defeats most of this by default, in almost every production environment worth worrying about. Deploy on Vercel, Netlify, or any modern host, and HTTPS is on unless you go out of your way to turn it off. The traffic is encrypted end to end, and a stranger sitting on the same network sees noise, not requests.

There's a temptation to think a native mobile app is safer here, since there's no browser tab exposing the network calls. That's not true, and it's worth being direct about it. Tools like Charles let anyone install a certificate and proxy their own device's traffic, watching every request a native app makes exactly the way DevTools watches a website. Hiding an API inside a mobile app is not a security boundary. It's just a slightly higher speed bump.

Two attributes from earlier in this course are worth a fast recap, because they're the foundation everything else in this post builds on.

  • HttpOnly blocks JavaScript from reading a cookie through document.cookie. Set it unless there's a specific reason a script on the page genuinely needs that value.
  • Secure ensures a cookie only travels over HTTPS, closing the door on it ever crossing the wire in plain text.

There's a third one that hasn't come up yet: SameSite.

SameSite tells the browser whether to attach a cookie to a request that originated from a different site. It has three settings, and each one trades a different amount of convenience for safety.

None sending a cookie on every cross-site request, Lax sending it only on top-level link navigation, and Strict blocking it entirely, with Lax now the modern browser default. ExpandNone sending a cookie on every cross-site request, Lax sending it only on top-level link navigation, and Strict blocking it entirely, with Lax now the modern browser default.

  • None sends the cookie everywhere, including requests kicked off by a completely different site. This used to be the default, and it's the most permissive option there is.
  • Strict never sends the cookie on a cross-site request, full stop. Click a link someone shared, and the destination site treats you as logged out, even if you have an active session there.
  • Lax sits in between: the cookie rides along on top-level navigation, like clicking a link, but gets withheld from background cross-site requests a page makes on its own.

Strict sounds like the obviously correct choice until you imagine the user experience. Someone shares a link to a private note, a friend clicks it, and instead of seeing the note, they see a login screen, because Strict decided a clicked link doesn't count as trustworthy enough. That's a real cost, not a hypothetical one.

Here's the detail that actually matters going forward: modern browsers now default to Lax even when SameSite is never set at all. That change happened a couple of years back, broke some things that quietly depended on the old None-by-default behavior, and raised the baseline safety of every cookie on the web that never opted into anything. It's one of the rare cases where doing nothing got safer on its own.

Site and Origin Are Not the Same Word

SameSite uses the word "site," and same-origin policy uses the word "origin." Those sound interchangeable. They are not, and the gap between them matters.

An origin, as covered earlier in this course, is the full protocol, host, and port tuple. https://app.example.com and https://billing.example.com are different origins, because host includes the entire subdomain.

A site is looser: roughly the registrable domain plus one label. Under that definition, app.example.com and billing.example.com count as the same site, even though they're different origins. Subdomains are generally fair game for "same site," which is exactly why SameSite cookies can flow between a company's own subdomains without extra configuration.

The Public Suffix List Closes the Obvious Hole

That "same site" definition breaks down fast on shared hosting. If vercel.app counted as one giant site, every project deployed there would count as the same site as every other project, and SameSite cookies would flow freely between complete strangers' apps.

This is the same domain-scoping danger covered a couple posts back with the leading-dot cookie trick, showing up again at the browser's own definition of what counts as one site.

The fix is a public, open registry called the Public Suffix List. Providers like Vercel and GitHub Pages register their own hosting domains on it, and every major browser respects that list. Once vercel.app is on it, the browser treats each subdomain under it as its own separate site, not one shared blob. Cookies stay scoped the way everyone assumed they already were.

The Rest of the Injection Family

SQL injection got its own post earlier in this chapter, but it's one member of a wider family, and the shape repeats every time.

  • Command injection: unsanitized input reaching a shell command, like calling out to Bash to list files and letting a user smuggle in ; rm -rf alongside a filename
  • Remote code execution: input reaching eval, Function, or an unsanitized exec call, turning data into running code
  • File upload vulnerabilities: accepting a file without verifying it's actually the type it claims to be, trusting the extension or a spoofable header instead of the content itself

Every one of these is the same root cause as SQL injection, wearing a different outfit: user input treated as instructions instead of data.

The practical fix is usually a safer built-in alternative that never needs to touch a shell at all. Use execFile with an allow-listed command instead of shelling out freely. Use Node's readdir instead of shelling out to ls just to list a directory. Reach for these before reaching for anything that hands a string straight to a shell.

Testing deserves a mention here too. Known-bad payloads belong in the test suite, the same way any other edge case does. Run ' OR 1=1--, a command injection string, and a mismatched file upload through the tests that guard these routes, and a regression gets caught before it ships instead of after.

What This Sets Up

Everything in this chapter, and the one before it, assumed the request itself was legitimate. A real user, on a real session, sending a request the server could reasonably expect.

The next thing this course tackles is what happens when that assumption is wrong, when the request looks completely legitimate and isn't.

The Essentials

  1. HTTPS defeats most man-in-the-middle attacks by default on any modern host. A native mobile app is not more hidden, tools like Charles proxy its traffic just as easily.
  2. HttpOnly and Secure block JavaScript access and plain-text transport. SameSite decides who gets to bring the cookie along at all.
  3. Modern browsers now default unset cookies to Lax, raising the baseline safety of cookies that never opted into anything.
  4. Site and origin are different words with different scopes. Origin is protocol, host, and port. Site is roughly the registrable domain plus one label.
  5. The Public Suffix List keeps shared hosts like vercel.app from being treated as one giant site that leaks cookies between every tenant.
  6. Command injection, remote code execution, and file upload vulnerabilities are the same root cause as SQL injection, wearing different outfits.

Next up: cross-site request forgery, the point where this course stops assuming the request came from where it claims to.

Further Reading and Watching