Repository navigation
Conversation
koraysrn
force-pushed
the
ai-prompt-fence-and-minmax-masking
branch
from
October 24, 2026 12:26
0d6d737 to
d4f006e
Compare
…ault The three standalone AI routes (describe-schema, explain, query-safety) placed database-derived text directly into the model prompt, so a table name, column comment or engine plan written by whoever can write to the database was read as the server's own instruction. Add a shared src/lib/ai/prompt-fence.ts that reuses the agent's fenceUntrustedContent envelope, and wrap the schema context, query and EXPLAIN plan of all three routes in it. The Data Profiler's AI summary sent a column's real min and max values, masked only where the results grid happened to mask them. Make the AI summary mask every column a masking pattern matches by default, decoupled from the grid's runtime toggle, and add MaskingConfig.aiSummaryMinMax so an operator can restore the grid's decision with "revealed".
Add unit tests for fenceForPrompt and fenceExplainPlan (surface labels, operation ids, marker neutralisation, plan serialisation), unit tests for maskAiSummaryValue (default-on masking, revealed policy, repeated column names, missing values, disabled patterns), and route-level tests that assert the three AI routes fence their prompt content and neutralise a marker written into the input. Add tests/security/ai-prompt-fence.test.ts as a closed-list guard: it enumerates src/app/api/ai and requires every AI route to call the shared fence, and proves the B109 scenario at runtime. Update the DataProfiler component tests so the AI summary masks min/max while the grid stays unmasked, and so aiSummaryMinMax "revealed" restores the grid decision.
Close B109 by deleting its backlog entry and adding B129 for the remaining browser-side masking gap. Update docs/AGENT.md citations, the AGENT_DATA_FLOW.md egress table and the "other AI surfaces" section, and register security control 0.10 in both docs/SECURITY.md and the PROGRAMME_CONTROL_IDS witness in scripts/security-check.mjs, moving the control-count assertion in tests/unit/security-check.test.ts from 47 to 48. Update the D85 auth-mock grep count to 55 for the new security test file so the backlog structure guard stays in step.
koraysrn
force-pushed
the
ai-prompt-fence-and-minmax-masking
branch
from
October 24, 2026 12:54
d4f006e to
b3d3f66
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The three standalone AI routes (describe-schema, explain, query-safety) put
database-derived text into the model prompt without any boundary, so a table
name, column comment or engine plan written by whoever can write to the
database was read by the model as the server's own instruction. This change
wraps that content in the same untrusted-content fence the agent runtime
already uses, and closes backlog entry B109.
Separately, the Data Profiler's AI summary sent a column's real min and max
values, masked only where the results grid happened to mask them. The summary
now masks every column a masking pattern matches by default, decoupled from
the grid's runtime toggle, with MaskingConfig.aiSummaryMinMax as the explicit
opt-out.
Type of Change
Related Issue
Closes # (none filed; this closes backlog entry B109 and adds B129)
Changes Made
Testing
Test Environment
Results
Screenshots (if applicable)
N/A
Checklist
Additional Notes
Design choices and alternatives:
Fence instead of sanitise. Sanitising would change meaning; the fence only labels where the server stopped talking, matching the agent boundary exactly.
Default min/max masking is "masked", not "revealed". min and max are real column values leaving the machine, so the safe default is to mask, with aiSummaryMinMax "revealed" as the explicit operator opt-out.
Server-side masking is left out of this PR. The profile route still returns raw values, so a host rendering its own profiler is not covered. That gap is recorded as backlog entry B129 rather than expanding this change.
Module size impact: the new shared module src/lib/ai/prompt-fence.ts is 2,162 bytes and pulls only src/lib/agent/untrusted-content.ts (7,863 bytes, zero imports, zero new npm dependencies).