Two releases landed on the same day from Simon Willison: Datasette 1.0a38, carrying a SQL injection security fix, and 0.65.3, which back-ports that same fix to the stable branch. The advisory is unusually specific about who should care. The issue affects Datasette instances that serve a mixture of public and private tables in the same database, with access governed by Datasette’s permissions system. Administrators running that configuration are advised to disable the execute-sql permission on the affected database to block users from reaching data they shouldn’t see.
That’s a small population of deployments. It’s also exactly the population Datasette has spent years courting.
The tension baked into the design
Datasette’s core pitch is that it turns a SQLite file into a browsable, queryable, API-addressable website — and a big part of that value is execute-sql, the ability for a visitor to type arbitrary SQL into a box and get results. That is not a bug in the product; it is the product. Layer a permissions system on top so some tables are public and some are private, and you’ve created a boundary that has to hold against an adversary who is, by design, allowed to write queries.
Every query engine that exposes SQL to semi-trusted users inherits this problem. The permission check happens at one layer — table visibility, row filters, route access — while the SQL executes at another. Anywhere the two layers can be made to disagree, you get exactly this class of bug. Datasette isn’t unusual here; it’s just honest about where the seam is.
The recommended mitigation is telling. Turning off execute-sql doesn’t patch anything. It removes the capability that makes the boundary load-bearing in the first place. That’s the right emergency advice, and it’s also a quiet admission that arbitrary SQL plus fine-grained authorization is a hard combination to get right.
Why the backport matters more than the alpha
Datasette 1.0 has been in alpha for a long stretch — 1.0a38 is a lot of alphas. Plenty of production deployments are still sitting on the 0.65.x line, which is precisely why 0.65.3 exists. Shipping a security fix only to a prerelease branch would have left the most conservative operators, the ones least likely to run an alpha in production, unpatched. Backporting is unglamorous maintenance work, and it’s the difference between an advisory that gets applied and one that doesn’t.
What to do
If you run Datasette purely over public data, this is a non-event; upgrade at your leisure. If you run it with private tables and Datasette-managed permissions, treat it as urgent: upgrade to 1.0a38 or 0.65.3, and consider whether execute-sql needs to be on for that database at all, patched or not.
The broader lesson generalizes past this one tool. If your data-exploration layer lets users author queries, the authorization model is your attack surface — and the safest privilege is the one you never granted. Splitting sensitive tables into a separate database file, rather than relying on per-table permissions inside a shared one, removes the seam entirely.