---
title: "Block cross-site form posts · Agent Wranglers"
url: https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/cross-site-requests
updated: 2026-10-20
licence: "All rights reserved"
---

# Block cross-site form posts

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Access and accounts](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts)
- Rule: Make sure a change of state only comes from your own pages, with `SameSite` cookies plus a token or an origin check.
- How: Never change anything on a GET request. For cookie logins, check `Sec-Fetch-Site` on every POST, PUT, PATCH and DELETE, and fall back to the `Origin` header. Refuse when neither proves the request came from your own origin. Or add a token to each form. `SameSite` alone does not stop attacks from your own subdomains. APIs that take a bearer token in a header are not exposed.
- Check: Send a POST to a change-of-state route with the test user's cookie and `Origin: https://evil.example.net`, then with `Sec-Fetch-Site: cross-site`. The server refuses both with 403. The same POST with your own origin still works.

Example:

```js
const UNSAFE = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
app.use((req, res, next) => {
  if (!UNSAFE.has(req.method)) return next();
  const site = req.get('sec-fetch-site');
  const sameOrigin = site ? site === 'same-origin' : req.get('origin') === 'https://example.com';
  return sameOrigin ? next() : res.sendStatus(403);
});
```

```python
# Python with Flask
UNSAFE = {"POST", "PUT", "PATCH", "DELETE"}

@app.before_request
def refuse_cross_site():
    if request.method not in UNSAFE:
        return
    site = request.headers.get("Sec-Fetch-Site")
    same_origin = site == "same-origin" if site else request.headers.get("Origin") == "https://example.com"
    if not same_origin:
        abort(403)
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers security testing playbook: https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/cross-site-requests`.

- Previous: [Lock down session cookies](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/session-cookies)
- Next: [Make password resets safe](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/password-reset)
- [Access and accounts](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts)
