datasette PR #2689: Replace token-based CSRF with Sec-Fetch-Site header protection

Simon Willison's Blog Tools

Summary

Datasette PR #2689 replaces token-based CSRF protection with Sec-Fetch-Site header-based protection, inspired by Go 1.25 and Filippo Valsorda's research, simplifying CSRF handling by eliminating the need for hidden form tokens.

No content available
Original Article
View Cached Full Text

Cached at: 04/20/26, 08:27 AM

# datasette PR #2689: Replace token-based CSRF with Sec-Fetch-Site header protection Source: https://simonwillison.net/2026/Apr/14/replace-token-based-csrf/ 14th April 2026 - Link Blog **datasette PR #2689: Replace token-based CSRF with Sec-Fetch-Site header protection (https://github.com/simonw/datasette/pull/2689)**. Datasette has long protected against CSRF attacks using CSRF tokens, implemented using my `asgi-csrf` (https://github.com/simonw/asgi-csrf) Python library. These are something of a pain to work with – you need to scatter forms in templates with `{{ csrf_token() }}` lines and then selectively disable CSRF protection for APIs that are intended to be called from outside the browser. I've been following Filippo Valsorda's research here with interest, described in this detailed essay from August 2025 (https://words.filippo.io/csrf/) and shipped as part of Go 1.25 (https://tip.golang.org/doc/go1.25#nethttppkgnethttp) that same month. I've now landed the same change in Datasette. Here's the PR description – Claude Code did much of the work (across 10 commits, closely guided by me and cross-reviewed by GPT-5.4) but I've decided to start writing these PR descriptions by hand, partly to make them more concise and also as an exercise in keeping myself honest. > - New CSRF protection middleware inspired by Go 1.25 and this research (https://words.filippo.io/csrf/) by Filippo Valsorda. This replaces the old CSRF token based protection. > - Removes all instances of `{{ csrf_token() }}` in the templates – they are no longer needed. > - Removes the `def skip_csrf(datasette, scope):` plugin hook defined in `datasette/hookspecs.py` and its documentation and tests. > - Updated CSRF protection documentation (https://docs.datasette.io/en/latest/internals.html#csrf-protection) to describe the new approach. > - Upgrade guide now describes the CSRF change (https://docs.datasette.io/en/latest/upgrade_guide.html#csrf-protection-is-now-header-based).

Similar Articles

datasette 1.0a27

Simon Willison's Blog

Datasette 1.0a27 released with major security improvements (modern CSRF headers), new RenameTableEvent for plugin compatibility, and various API enhancements including improved upsert handling and database locking fixes.

datasette 1.0a38

Simon Willison's Blog

Datasette 1.0a38 fixes a SQL injection vulnerability affecting instances that serve mixed public and private tables, with the fix also backported to Datasette 0.65.3.

datasette-auth-tokens 0.4a13

Simon Willison's Blog

Release of datasette-auth-tokens 0.4a13, an authentication tokens plugin for Datasette by Simon Willison.

datasette-referrer-policy 0.1

Simon Willison's Blog

Release of datasette-referrer-policy 0.1, a Datasette plugin to fix OpenStreetMap tile display by overriding the default no-referrer header.

datasette-apps 0.1a2

Simon Willison's Blog

Datasette-apps 0.1a2 adds app CSP permissions, improved stored query picker with keyboard navigation, and fixes for link modals and full-screen mode.