Security
- The ReadOnly statement whitelist now unwraps and validates parenthesized query heads (
(SELECT ...), alone or combined viaUNION/INTERSECT/EXCEPT, with trailingORDER BY/LIMIT/OFFSET/FETCHclauses). Previously a statement starting with(carried no readable verb and was waved through unvalidated. Statements whose shape cannot be read are now rejected instead of assumed harmless. - Whitelist recursion depth is bounded (64 nested query heads), so an adversarial run of nested parentheses is rejected cleanly instead of crashing the process with an uncatchable
StackOverflowException. - Bumped the transitive native
SQLitePCLRaw.lib.e_sqlite3to 3.53.3 — the 2.1.11 thatMicrosoft.EntityFrameworkCore.Sqlitebrings in has a known high-severity vulnerability (GHSA-2m69-gcr7-jv3q).
Changed
- The executor's wrapper transaction now uses the provider-default isolation level instead of
ReadUncommittedin ReadOnly mode, eliminating dirty reads on SQL Server (uncommitted data the LLM would present as fact). SQLite ReadOnly uses a deferredBEGIN, which is compatible withPRAGMA query_only. - The schema description is now cached for the application lifetime (on the options singleton, keyed by
DbContexttype) instead of per request scope — the EF model walk and the connection open for server info run once. - README now states explicitly that include/exclude is schema hiding, not access control: the executor does not block SQL referencing excluded tables or columns, so genuinely sensitive data must be protected with database permissions.
Fixed
AgentQLChatOptions.MaxOutputTokenswas documented but never applied; it now flows into chat requests whenever the per-request options leave it unset.- The Anthropic provider honors an explicitly configured
Endpointinstead of silently ignoring it. - The self-correction guard no longer skips a genuine user question that merely mentions
<system-reminder>when restating the question; only messages that start with the injected reminder tag are skipped. - A malformed
WITH x AS (with an unterminated body no longer throws inside the whitelist validator; it is reported as malformed and neutralized like any other violation.
Full Changelog: v0.3.0...v0.4.0