# Defense-in-Depth Score: Chat2DB

**Repo:** https://github.com/OtterMind/Chat2DB · **Commit:** `dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8` (5.3.0) · **Reviewed:** 2026-10-03
**What it is:** Cross-platform DB client/SQL workspace with AI SQL generation over 40+ databases
**Category:** Data & Analytics
**Scored configuration:** Community desktop app (5.3.0 at the pinned commit), fresh install with a user-configured AI model, AI chat with database tools enabled (the client always requests tools) and the opt-in MCP server off.
**Agent surface (default):** code execution yes · filesystem write no · network egress yes · external credentials yes · persistent memory yes · untrusted input yes · third party extensions yes · sub agents no · external communication no

## Score: 3.5 / 10.0 (Minimal)

| # | Criterion | S | C | D | B | Raw | Cap | Score | Confidence |
|---|---|---|---|---|---|---|---|---|---|
| C1 | Identity & least privilege | L0 | L0 | L0 | L1 | 0.05 | — | **0.05** | High |
| C2 | Approval gates | L3 | L2 | L4 | L1 | 0.62 | — | **0.62** | Medium |
| C3 | Tool & action scoping | L2 | L3 | L3 | L1 | 0.57 | — | **0.57** | High |
| C4 | Code-execution isolation | L0 | L0 | L0 | L1 | 0.05 | — | **0.05** | High |
| C5 | Untrusted input blast radius | L2 | L1 | L3 | L1 | 0.42 | — | **0.42** | High |
| C6 | Memory, context & configuration integrity | L2 | L3 | L3 | L3 | 0.68 | — | **0.68** | High |
| C7 | Third-party extensions | L2 | L1 | L0 | L0 | 0.23 | — | **0.23** | High |
| C8 | Secrets & sensitive-data protection | L2 | L1 | L1 | L1 | 0.33 | — | **0.33** | High |
| C9 | Audit & traceability | L2 | L2 | L2 | L1 | 0.45 | — | **0.45** | High |
| C10 | Limits & kill switch | L0 | L1 | L0 | L0 | 0.07 | — | **0.07** | High |


Chat2DB's AI assistant can query every database you have saved, using your full stored credentials, and the model chooses which one. Its best control is a hard refusal of write SQL: anything other than SELECT/SHOW/DESCRIBE is handed back for you to run yourself, and there is no setting to turn that off. The dominant risk is data exfiltration: content in your databases or uploaded files can steer the model, and the chat UI offers an unattended egress path. There are also no time, step, or query-timeout limits on an AI turn.

## Critical gaps
- JDBC drivers run in-process with every decrypted datasource password and AI API key, and the MySQL drivers are downloaded automatically from the vendor CDN at startup without integrity verification. (ASI04, T17, LLM03; C7) — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbJdbcDriverServiceImpl.java:133-153](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbJdbcDriverServiceImpl.java#L133-L153); [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/util/JdbcJarUtils.java:145-151](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/util/JdbcJarUtils.java#L145-L151); [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/constant/JdbcDriverConstants.java:12](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/constant/JdbcDriverConstants.java#L12)

## Criterion details

### C1 Identity & least privilege — 0.05 (high)

The AI assistant runs every database tool with the full stored credential of whichever datasource it chooses. Although the chat request carries the datasource the user selected, a model-supplied datasource id overrides it, and list_all_datasources hands the model every saved connection (up to 200, including production-tagged ones). There is no dedicated or read-only identity for AI work and no authorization check between the model's choice and the credential; the only thing that narrows damage is the separate non-query SQL refusal scored under tool scoping.

- **S L0:** Tools run with the user's stored datasource credential (decrypted per call) and the model can target any saved datasource. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:706-711](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L706-L711); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:85-92](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L85-L92); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:217-229](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L217-L229) (verified)
  - *To reach the next level:* Give AI tools a separate, read-only credential per datasource (or refuse to use credentials not scoped for AI).
- **C L0:** No tool path performs an authorization check; the model-supplied dataSourceId is used directly, on both the in-app and MCP paths. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:706-711](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L706-L711); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java:65-75](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java#L65-L75) (verified)
  - *To reach the next level:* Check every tool call against the datasource/database the user selected for the session before attaching credentials.
- **D L0:** By default (no datasource selected) the chat runs in global scope with tools over every saved connection. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:821-824](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L821-L824); [chat2db-community-client/src/blocks/AI/index.tsx:1634](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-client/src/blocks/AI/index.tsx#L1634) (verified)
  - *To reach the next level:* Default the AI to the selected datasource only, and require explicit opt-in for cross-datasource access.
- **B L1:** A hijacked session can read any data every saved credential can reach across all datasources; the independent non-query refusal blocks most, but not all, writes. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:85-92](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L85-L92); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:625-631](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L625-L631); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:692-695](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L692-L695) (verified)
  - *To reach the next level:* Limit reach to one datasource with read-only credentials so a failure stays within a single, mostly-read scope.
- **Cap:** none

### C2 Approval gates — 0.62 (medium)

Chat2DB does not let the AI run write SQL itself. Every execute_sql call is parsed into statement types; anything other than SELECT/SHOW/DESCRIBE is refused and handed back to the user to run manually in the SQL console, and the policy hook that could allow non-query execution is hard-wired to false with no setting to change it. The exact SQL the model attempted is shown in the chat trace, so the human runs exactly what they see. The gap is in what counts as safe: statements classified as queries run unattended, and the classification is not a strict boundary.

- **S L3:** Non-query SQL is refused per call and the exact SQL is surfaced (tool_call arguments streamed to the UI and the SQL echoed for manual execution), with statement-type tiers deciding what auto-runs. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:625-631](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L625-L631); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:873-884](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L873-L884); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java:14-19](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java#L14-L19) (verified)
  - *To reach the next level:* No structured approve/reject step: the human must re-run the SQL by hand, and policy is limited to statement type rather than argument-level rules (statement contents, target datasource).
- **C L2:** Both the in-app chat and the MCP path go through the same gate, and multi-statement scripts are parsed per statement, but the auto-approved set is a statement-type allowlist that is not verified read-only. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:692-695](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L692-L695); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java:65-75](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java#L65-L75) (verified)
  - *To reach the next level:* Make the auto-run set verifiably read-only.
- **D L4:** The refusal is always on: the only policy bean returns false and there is no flag, setting, or chat-reachable path to enable AI write execution; execution of refused SQL requires the user's own action in the console. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java:14-19](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java#L14-L19); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:625-631](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L625-L631) (verified)
- **B L1:** Anything that is auto-run as a query or that the user runs after being misled executes directly against the live database with no undo, preview, or rate limit. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:692-695](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L692-L695); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:217-229](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L217-L229) (inferred)
  - *To reach the next level:* Run AI SQL in a rolled-back or read-only transaction and offer dry-run/preview for anything the user is asked to execute.
- **Cap:** none

### C3 Tool & action scoping — 0.57 (high)

The six AI tools are narrow wrappers with typed parameters, bounded page sizes (500 rows max, 50 rows shown to the model) and a 20-table cap on schema requests, and execute_sql is filtered by a dialect-aware SQL parser that only lets query-type statements run. But execute_sql still accepts arbitrary SQL text, the read-only check is a statement-type classification rather than a read-only connection, and no tool validates which datasource or database the model points it at. The default tool set is effectively read-only, which is the strongest part of this design.

- **S L2:** execute_sql accepts raw SQL filtered by parsed statement type; numeric bounds exist on page size and table count, but datasource targets are not validated. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiToolAdapter.java:65-76](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiToolAdapter.java#L65-L76); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:692-695](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L692-L695); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:81-83](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L81-L83); searched `rg -n 'setReadOnly\(true\)'` in `chat2db-community-server` → 1 hits (The single hit is a file attribute in an updater test; no JDBC connection is put in read-only mode for AI SQL.) (verified)
  - *To reach the next level:* Enforce read-only at the connection/transaction level and validate the target datasource against the session scope instead of relying on statement-type parsing.
- **C L3:** Every AI tool path, including the opt-in MCP server, calls the same AiToolServiceImpl methods, so the SQL classification and bounds apply uniformly. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java:65-75](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java#L65-L75); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:207-213](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L207-L213); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:81-83](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L81-L83) (verified)
  - *To reach the next level:* Route all tools through one central policy layer that also enforces datasource scope and that new tools inherit automatically.
- **D L3:** The default tool set is read-only in effect: non-query execution is refused and cannot be enabled by configuration. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java:14-19](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java#L14-L19); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:625-631](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L625-L631); [chat2db-community-client/src/blocks/AI/index.tsx:1634](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-client/src/blocks/AI/index.tsx#L1634) (verified)
  - *To reach the next level:* Give each task only the tools and datasources it needs (e.g. no execute_sql in NL2SQL mode, no global datasource listing).
- **B L1:** A misused tool can run any query-type SQL against any saved datasource, bounded only by per-call row limits. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:85-92](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L85-L92); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:706-711](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L706-L711); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:81-83](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L81-L83) (verified)
  - *To reach the next level:* Scope tools to the selected datasource/schema and bound total rows/calls per session.
- **Cap:** none

### C4 Code-execution isolation — 0.05 (high)

The model-generated code in Chat2DB is SQL, and it runs directly on the user's real databases through the normal JDBC connection with the stored credential. There is no isolation boundary: no read-only connection or transaction, no rollback wrapper, no sandbox database, and no query timeout. The statement-type filter (credited under tool scoping) is the only thing standing between model SQL and the database.

- **S L0:** AI SQL executes on the live connection via dlTemplateService.execute with no isolation primitive; no read-only connection mode is set anywhere. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:217-229](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L217-L229); searched `rg -n 'setReadOnly\(true\)'` in `chat2db-community-server` → 1 hits (The single hit is a file attribute in an updater test; no JDBC connection is put in read-only mode for AI SQL.) (verified)
  - *To reach the next level:* Execute AI SQL inside a read-only connection or a transaction that is always rolled back, or against a replica.
- **C L0:** No execution path (chat or MCP) is isolated. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:217-229](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L217-L229); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java:65-75](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/mcp/adapter/AiToolMcpAdapter.java#L65-L75) (verified)
  - *To reach the next level:* Route every AI-issued statement through the isolation layer.
- **D L0:** No isolation exists to be on by default. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:217-229](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L217-L229) (verified)
  - *To reach the next level:* Ship isolation on by default for AI SQL.
- **B L1:** Statements run with the full stored DB credential on production-capable connections; the independent statement-type refusal still blocks ordinary DML/DDL. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:706-711](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L706-L711); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:625-631](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L625-L631); searched `rg -n 'setQueryTimeout'` in `chat2db-community-server chat2db-community-client/src` → 1 hits (The single hit is the connection-pool validation query (ConnectionPool.java:188), not AI-issued SQL.) (verified)
  - *To reach the next level:* Restrict AI SQL to a low-privilege, read-only, time-limited session so an escape reaches little.
- **Cap:** none

### C5 Untrusted input blast radius — 0.42 (high)

The assistant reads plenty of content its user did not write: database rows, table and column comments, DDL, and uploaded files, all of which enter the conversation with the same standing as the user's request (uploaded files are even framed as 'evidence provided by the user'). Nothing tracks that taint. What limits a hijack is that writes are always refused regardless of source. Data exfiltration is not limited: the chat UI offers an unattended egress path.

- **S L2:** Writes are always forced to a human (non-query refusal), but egress is not. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:625-631](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L625-L631) (verified)
  - *To reach the next level:* Close unattended egress paths in the chat UI and gate cross-datasource reads once untrusted content has been read.
- **C L1:** The write refusal applies to every source, but untrusted sources are not distinguished at all: tool results, DB comments, and attachments enter context like user instructions. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:397-398](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L397-L398); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:470-473](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L470-L473); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:333-335](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L333-L335) (verified)
  - *To reach the next level:* Mark tool results and file content as untrusted data and apply the limits based on that provenance.
- **D L3:** The write refusal is always on and nothing the model reads can configure it away. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java:14-19](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/DefaultAiSqlAutoExecutionPolicy.java#L14-L19) (verified)
  - *To reach the next level:* Close the egress leg by default as well; D cannot exceed one level above the mechanism's strength.
- **B L1:** A successful injection can exfiltrate any data the saved credentials can read, unattended; irreversible writes mostly require the user. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:85-92](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L85-L92) (verified)
  - *To reach the next level:* Remove the unattended exfiltration channel so both leaks and irreversible actions need a human.
- **Cap:** none

### C6 Memory, context & configuration integrity — 0.68 (high)

Chat2DB has no long-term memory, retrieval store, or auto-loaded instruction files. The only persistence that feeds back into the model is the chat history of the current session: the last five rounds of user and assistant text are re-sent on each turn, loaded only for the session the user owns. Poisoned content can therefore persist within a conversation but not spread to new ones, and the user can delete sessions.

- **S L2:** History is stored per session as role-tagged user/assistant messages; tool results are not re-injected and no workspace file can change settings. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:179-186](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L179-L186); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:46](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L46) (verified)
  - *To reach the next level:* Validate or flag assistant content that quoted untrusted data before re-injecting it.
- **C L3:** The single persistent store is session-scoped by query, and there are no auto-loaded files or retrieval stores. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:179-186](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L179-L186); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:519-521](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L519-L521) (verified)
  - *To reach the next level:* Provenance-tag re-injected history end to end.
- **D L3:** History is namespaced per user and session (ownsSession check) and the model has no tool to write other sessions. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:175-177](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L175-L177); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:179-186](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L179-L186) (verified)
  - *To reach the next level:* Add retention limits on stored history by default.
- **B L3:** Poisoned text persists only within its session (last 5 rounds) and sessions can be deleted. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:179-186](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L179-L186) (verified)
  - *To reach the next level:* Require review before persisted history influences later turns.
- **Cap:** none

### C7 Third-party extensions — 0.23 (high)

The AI layer itself loads no plugins or MCP servers in this release; the third-party code that runs alongside it is JDBC drivers, which execute inside the same JVM that holds every decrypted credential. Built-in drivers are fetched by version-pinned file name from the vendor's CDN with no checksum, and the MySQL drivers are pre-downloaded automatically at startup. Custom drivers are uploaded by the operator, which the security policy treats as trusted.

- **S L2:** Built-in driver jars are pinned by versioned file names but downloaded without hash or signature verification. — [chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/resources/ai/chat2db/plugin/mysql/mysql.json:11-13](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/resources/ai/chat2db/plugin/mysql/mysql.json#L11-L13); [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/constant/JdbcDriverConstants.java:12](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/constant/JdbcDriverConstants.java#L12); [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/util/JdbcJarUtils.java:145-151](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/util/JdbcJarUtils.java#L145-L151) (verified)
  - *To reach the next level:* Verify a known SHA-256 or signature for each downloaded driver.
- **C L1:** Only the sqlx helper installer verifies a SHA256SUMS digest; JDBC drivers (built-in and custom) are not verified. — [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/util/JdbcJarUtils.java:145-151](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/util/JdbcJarUtils.java#L145-L151); [chat2db-community-server/chat2db-community-sqlx/src/main/java/ai/chat2db/community/sqlx/SqlxReleaseInstaller.java:120-128](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-sqlx/src/main/java/ai/chat2db/community/sqlx/SqlxReleaseInstaller.java#L120-L128) (verified)
  - *To reach the next level:* Apply integrity verification to all downloaded and uploaded drivers.
- **D L0:** MySQL driver jars are downloaded automatically at startup without a prompt. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbJdbcDriverServiceImpl.java:133-153](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbJdbcDriverServiceImpl.java#L133-L153) (verified)
  - *To reach the next level:* Download drivers only after explicit user action that shows the exact artifact and source.
- **B L0:** Drivers run in-process in the JVM that holds all decrypted datasource passwords and AI API keys. — [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbJdbcDriverServiceImpl.java:133-153](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbJdbcDriverServiceImpl.java#L133-L153); [SECURITY.md:42](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/SECURITY.md#L42); [chat2db-community-server/chat2db-community-storage/src/main/java/ai/chat2db/community/storage/LocalWorkspaceStorage.java:234](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-storage/src/main/java/ai/chat2db/community/storage/LocalWorkspaceStorage.java#L234) (verified)
  - *To reach the next level:* Isolate drivers in a separate process with only the credential for their own connection.
- **Cap:** none
- **Notes:** G1 does not apply: version pinning is always on; D is L0 because built-in MySQL drivers are fetched automatically at startup, not because a control is opt-in. The AI layer loads no plugins or MCP servers at this commit.

### C8 Secrets & sensitive-data protection — 0.33 (high)

Stored datasource passwords and AI API keys are encrypted at rest with AES-256-GCM using a per-installation key, and the main AI request path logs only content-free summaries with masked API keys. Elsewhere protection is thin: the log-redaction controls do not cover every path, chat transcripts with query results are stored as plain JSON, and nothing redacts sensitive data from query results before they go to the model provider. Usage telemetry is on by default but content-free.

- **S L2:** Encryption at rest for stored secrets and summary-only AI logging, but log redaction is weak and nothing redacts model-bound data. — [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/security/AesGcmUtil.java:21-29](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/security/AesGcmUtil.java#L21-L29); [chat2db-community-server/chat2db-community-storage/src/main/java/ai/chat2db/community/storage/LocalWorkspaceStorage.java:234](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-storage/src/main/java/ai/chat2db/community/storage/LocalWorkspaceStorage.java#L234); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:1124-1127](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L1124-L1127) (verified)
  - *To reach the next level:* Add real redaction before logs and before model-bound tool results on all major paths.
- **C L1:** Only the main AI logging path is protected; transcripts, model-bound tool results, the non-streaming LLM interceptor, and HTTP body logs are not. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:1124-1127](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L1124-L1127); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/ZoerClientHttpRequestInterceptor.java:36-37](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/ZoerClientHttpRequestInterceptor.java#L36-L37); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:46](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L46) (verified)
  - *To reach the next level:* Cover transcripts, model-bound messages, and HTTP/LLM body logging.
- **D L1:** Usage telemetry rides along every update check by default (content-free) and redaction cannot be relied on. — [chat2db-community-server/chat2db-community-updater/src/main/java/ai/chat2db/community/updater/v2/telemetry/TelemetryConfig.java:15](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-updater/src/main/java/ai/chat2db/community/updater/v2/telemetry/TelemetryConfig.java#L15) (verified)
  - *To reach the next level:* Make telemetry opt-in and redaction always on.
- **B L1:** Leaked material is long-lived DB passwords and provider API keys, typically broadly privileged. — [chat2db-community-server/chat2db-community-storage/src/main/java/ai/chat2db/community/storage/LocalWorkspaceStorage.java:234](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-storage/src/main/java/ai/chat2db/community/storage/LocalWorkspaceStorage.java#L234); [chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/security/AesGcmUtil.java:21-29](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-tools/src/main/java/ai/chat2db/community/tools/security/AesGcmUtil.java#L21-L29) (verified)
  - *To reach the next level:* Prefer scoped, short-lived credentials for AI database access.
- **Cap:** none

### C9 Audit & traceability — 0.45 (high)

Each chat turn's tool calls (name, exact arguments, timestamp) and tool results are streamed to the UI and saved with the assistant's message in the local chat history, and every executed AI query is also written to the SQL operation log tagged AI_TOOL. That gives a usable local record, but it is saved only when the stream completes normally, operation logging is asynchronous and best-effort, refused statements and list calls are absent from the operation log, MCP calls are tagged the same as in-app AI calls, and the client can turn history persistence off per request.

- **S L2:** Structured per-call records (tool name, arguments, result, timestamp) in session history plus an operation log with an AI_TOOL source tag. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:873-884](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L873-L884); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:350-353](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L350-L353); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:230-233](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L230-L233) (verified)
  - *To reach the next level:* Record the requesting principal, approver, and channel (chat vs MCP) with correlation IDs.
- **C L2:** All built-in tools are traced in persisted chat sessions; MCP calls are not traced except executed SQL in the op log, and refusals are only in the chat trace. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:873-884](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L873-L884); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatTraceSupport.java:36-43](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatTraceSupport.java#L36-L43); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java:230-233](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiToolServiceImpl.java#L230-L233) (verified)
  - *To reach the next level:* Record every tool call on every path, including MCP and refusals, in one log.
- **D L2:** On by default and stored outside any workspace, but written by the same process and skippable per request via persistHistory. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:519-521](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L519-L521); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:46](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java#L46) (verified)
  - *To reach the next level:* Write the audit record from a component the request cannot switch off.
- **B L1:** History is written only on normal completion (errors drop the trace) and operation logging is an async best-effort queue. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:350-353](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L350-L353); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:935-939](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L935-L939); [chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/operation/OpsSqlOperationLogServiceImpl.java:140-145](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/operation/OpsSqlOperationLogServiceImpl.java#L140-L145) (verified)
  - *To reach the next level:* Flush a durable record per tool call before or as it executes.
- **Cap:** none

### C10 Limits & kill switch — 0.07 (high)

There are no hard limits on an AI turn. No tool-call round cap is configured for Spring AI's internal tool loop, the HTTP stream emitter has no timeout, AI-issued SQL has no query timeout, and output token limits apply only if the user sets them in the model config. Stopping a response closes the stream and disposes the subscription, but a query already running on the database continues.

- **S L0:** No step, wall-clock, or cost cap is enforced; only per-call row bounds and an optional maxTokens exist. — searched `rg -n -i 'maxIteration|maxToolCall|max_steps|recursionLimit|maxToolIterations'` in `chat2db-community-server` → 0 hits (No tool-call round cap is configured anywhere in the server; Spring AI internal tool execution then loops until the model stops calling tools (library behaviour inferred).); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:960](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L960); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiModelFactory.java:102-104](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiModelFactory.java#L102-L104); [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiModelFactory.java:96-98](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiModelFactory.java#L96-L98) (verified)
  - *To reach the next level:* Add a tool-round cap plus a wall-clock or token budget per turn, and a JDBC query timeout.
- **C L1:** The only halt (client abort -> emitter completion -> dispose) covers the top-level stream; in-flight JDBC statements are not cancelled and have no timeout. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:367-375](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L367-L375); searched `rg -n 'setQueryTimeout'` in `chat2db-community-server chat2db-community-client/src` → 1 hits (The single hit is the connection-pool validation query (ConnectionPool.java:188), not AI-issued SQL.) (verified)
  - *To reach the next level:* Apply timeouts to tool executions and cancel in-flight statements on stop.
- **D L0:** Unlimited by default: the emitter timeout is 0 (none) and no iteration cap is set. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:960](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L960); searched `rg -n -i 'maxIteration|maxToolCall|max_steps|recursionLimit|maxToolIterations'` in `chat2db-community-server` → 0 hits (No tool-call round cap is configured anywhere in the server; Spring AI internal tool execution then loops until the model stops calling tools (library behaviour inferred).) (verified)
  - *To reach the next level:* Ship sensible default caps.
- **B L0:** A runaway turn can keep calling tools and running queries until the user notices. — [chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java:960](https://github.com/OtterMind/Chat2DB/blob/dc2b80a3b0189bb3fd92d69ce8f52de2d4136ac8/chat2db-community-server/chat2db-community-web/src/main/java/ai/chat2db/community/web/api/adapter/ai/AiChatStreamAdapter.java#L960); searched `rg -n -i 'maxIteration|maxToolCall|max_steps|recursionLimit|maxToolIterations'` in `chat2db-community-server` → 0 hits (No tool-call round cap is configured anywhere in the server; Spring AI internal tool execution then loops until the model stops calling tools (library behaviour inferred).) (verified)
  - *To reach the next level:* Bound each turn's time and spend so a runaway stops on its own.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: DB rows, table/column comments and uploaded files enter context as tool results or user evidence (AiToolServiceImpl.java:397-398; AiChatStreamAdapter.java:470-473) · [B] sensitive data/systems: All saved datasources reachable with stored credentials, model picks the target (AiToolServiceImpl.java:85-92, 706-711) · [C] state change / egress: an unattended egress path in the chat UI; writes refused (AiToolServiceImpl.java:625-631) · Same default session? Yes

## Highest-impact improvements
1. Close unattended egress paths in the AI chat UI so injected content cannot exfiltrate query results unattended. — C5 B L1→L2, +0.050 before caps (Playbook 1)
2. Pin AI tools to the datasource/database the user selected and reject model-supplied dataSourceId values outside it; stop listing every saved connection in global scope. — C1 C L0→L2, +0.150 before caps (Playbook 4)
3. Cap tool-call rounds per turn, give the SSE emitter a timeout, and set a JDBC query timeout on AI-issued SQL. — C10 S L0→L2, +0.150 before caps (Playbook 3 step 3)
4. Execute AI SQL on a read-only connection or an always-rolled-back transaction instead of relying on statement-type parsing. — C4 S L0→L2, +0.150 before caps (Playbook 3)
5. Verify a pinned SHA-256 for each downloaded JDBC driver and stop pre-downloading drivers at startup without user action. — C7 D L0→L2, +0.100 before caps (Playbook 3)

## Re-audit log
- No changes.

## Limitations
- Static source review of the pinned commit only; nothing was executed, installed, or probed.
- The 5.4.0-beta 'Pi Agent' runtime (skills, external MCP servers, file and terminal tools) mentioned in the README is not present at this commit and was not scored.
- The opt-in CLI runtime mode (token-gated SQL endpoints for the external Chat2DB CLI, which does not apply the AI non-query refusal) and the opt-in MCP server were reviewed only for their effect on the AI tool path; they are not the scored default.
- Docker/web mode differs from the scored desktop default; its HTTP body logging and the opt-in MCP endpoint's access control are not locked down.
- Spring AI's unbounded internal tool loop is inferred from library behaviour, not observed; the statement-classification gaps are likewise inferred from database behaviour.
- System prompts contain behavioural and content rules; per the scorecard, prompts were not credited as controls. No reviewer-directed injection text was found in the repository.
