From 696957aa5ec0145477d2be38405b9b651c054642 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 2 Oct 2026 00:09:38 +0200 Subject: [PATCH] Issue 193: proven on a throwaway server, fixed for postgres by mesh-catalog PR 209; mssql has the same hole --- .../00-report.md | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/04-ISSUES/193-the-store-seats-read-only-query-is-read-only-by-convention/00-report.md b/04-ISSUES/193-the-store-seats-read-only-query-is-read-only-by-convention/00-report.md index 810a6a7..4b8afbb 100644 --- a/04-ISSUES/193-the-store-seats-read-only-query-is-read-only-by-convention/00-report.md +++ b/04-ISSUES/193-the-store-seats-read-only-query-is-read-only-by-convention/00-report.md @@ -2,7 +2,7 @@ status: located opened: 2026-10-02 located-in: [mesh-catalog modules/postgres/client.ts (readOnlyQuery)] -fixed-by: +fixed-by: [mesh-catalog PR 209 (postgres; open)] amended-design: --- @@ -51,3 +51,30 @@ so that includes anyone logged in on a machine running the console. instead of the command-line client, so a row is an object keyed by its columns. - **The check 0159 lacks:** a test that sends a commit followed by a write and asserts the write is refused and nothing changed. Another asserts a two-column row comes back keyed by both columns. + +## Proven, 2026-10-02 + +On a throwaway server — the same engine image, no network, reached over a socket — the module's code +from the catalogue's main branch ran `COMMIT; COPY (select 1) TO PROGRAM ''` and **the +command ran on the database host** as the server's own user. `COMMIT; DROP TABLE t` executed the drop +outside the read-only transaction; the wrapper's own trailing rollback happened to undo it, which a +caller ending their statement with a commit of their own would get past (not tried). Nothing was tried +against the live store. + +The fix (mesh-catalog PR 209) runs the caller's statement as a login granted `pg_read_all_data` and +nothing else, read-only by its role and its session, with a password the mesh mints as one of the +module's own secrets; without that password the call is refused rather than run as the admin. On the +same throwaway server every escape above, and `SET ROLE`, `RESET SESSION AUTHORIZATION`, turning +read-only off, creating a table, altering the role and reading a server file, is refused; a plain +select comes back keyed by its columns. One attempt — turning the transaction's read-only off, then +deleting — got past the first layer and was stopped by the second, which is why both exist. + +**Not answered by the statement-count fix proposed above.** The command-line client sends one string +in one message, so several statements still arrive together. They are harmless as the reader, and +refusing them is left to whoever moves the module to a driver. + +## The same hole, elsewhere + +The `mssql` module wraps a caller's statement the same way (`BEGIN TRANSACTION; … ROLLBACK;` as its +administrator) for its own `mssql_query` tool. It holds no seat, but the console may call it. It +needs the same change: a login that can only read, and no wrapper as text. Open.