Skip to content

Full-text search has no cost bound — a valid query can block the event loop (server concern) #149

Description

@cuibonobo

From the 2026-08 security pass. Low severity, and the code already acknowledges it — filing so it's tracked as a server requirement rather than living only in a source comment.

Problem

The FTS sanitizers (sanitizeFts4Query/sanitizeFts5Query) cap query-grammar complexity (wildcards stripped, NEAR neutralized, paren depth capped) — but not query cost. A syntactically valid search over a large index can still be expensive, and both SQLite engines run synchronously in-process: sql.js is WASM that blocks the JS event loop, and native node:sqlite blocks the calling thread. sanitizeFts4Query's own doc comment states a timeout "is not implementable for a synchronous, in-process SQLite engine … out of scope here."

Fine at personal-stack scale (you're only DoSing yourself). On haverstack/server, one expensive search blocks every other request on that thread.

Direction (server-side, not a core code change)

Nothing to fix in the sanitizers — the mitigation belongs to whoever runs the engine under load:

  • Run record-adapter queries off the request/event thread (worker thread per connection, or a worker pool), so a slow query can be interrupted via sqlite3_interrupt / worker termination and can't stall the loop.
  • Apply a per-request query timeout at that boundary.
  • Consider a spec sentence under §Queries or the wire format: full-text search is best-effort on cost; a server SHOULD bound query execution time and MAY return a typed error (candidate: reuse bad_request, or a new timeout code) when it does.

Work item

  • Spec sentence documenting FTS as cost-unbounded in-process, with the server-side bounding expectation; decide whether a timeout gets a wire code

Cross-refs: security pass 2026-08; #72 (streaming/buffering — same "synchronous in-process engine under server load" theme); the auth/server RFCs #138/#139.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions