mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 08:01:25 +00:00
924f9c7e8d
draft.value is a json column (not jsonb), so a client could store a U+0000 escape in it. Any later text extraction (`->>` / `to_jsonb`) on such a value raises 22P05 "unsupported Unicode escape sequence" — one poisoned draft 500'd the whole GET /drafts/list, silently hiding the home-page "This workspace has N drafts" banner (and breaking the global drafts page). Prevent it at the source: sanitize the value in update_draft (the only path that writes client-supplied draft content) so a NUL never reaches the column. strip_json_nul does a single backslash-parity-aware byte pass that removes real NUL escapes (values and keys alike) while leaving a legitimate escaped backslash intact — O(n) with no serde_json::Value tree to allocate, important because the slow path is also hit by any value legitimately containing the text after a backslash (e.g. script source). The clean path is a single substring check. A SQL migration scrubs rows written before this, gated to genuinely-poisoned rows (a real NUL makes value::jsonb raise, distinguishing it from a legitimately escaped backslash). With the data clean, no read-side query needs to change. Tests: unit tests for the strip helper (escaped-backslash no-op, real+literal collision, odd-backslash-run parity, nested keys/values) and an integration test that POSTs a NUL-bearing draft and asserts it is stored and listed NUL-free (fails without the strip). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
25 lines
1.1 KiB
SQL
25 lines
1.1 KiB
SQL
-- Fixture for the draft NUL-byte write-sanitization regression test.
|
|
-- Just a workspace + admin user + token; the test itself POSTs a draft whose
|
|
-- value carries a U+0000 and asserts it is stored (and listed) NUL-free.
|
|
|
|
INSERT INTO workspace (id, name, owner) VALUES
|
|
('dnul-ws', 'DNUL WS', 'dnul-admin');
|
|
|
|
INSERT INTO workspace_key (workspace_id, kind, key) VALUES
|
|
('dnul-ws', 'cloud', 'dnul-key');
|
|
|
|
INSERT INTO workspace_settings (workspace_id) VALUES
|
|
('dnul-ws');
|
|
|
|
INSERT INTO group_ (workspace_id, name, summary, extra_perms) VALUES
|
|
('dnul-ws', 'all', 'All users', '{}');
|
|
|
|
INSERT INTO password(email, password_hash, login_type, super_admin, verified, name, username)
|
|
VALUES ('dnul-admin@windmill.dev', 'x', 'password', true, true, 'DNUL Admin', 'dnul-admin');
|
|
|
|
INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
|
|
('dnul-ws', 'dnul-admin@windmill.dev', 'dnul-admin', true, 'Admin');
|
|
|
|
INSERT INTO token(token_hash, token_prefix, token, email, label, super_admin)
|
|
VALUES (encode(sha256('DNUL_ADMIN_TOKEN'::bytea), 'hex'), 'DNUL_ADMIN', 'DNUL_ADMIN_TOKEN', 'dnul-admin@windmill.dev', 't', true);
|