fix(sqlite): bound .dump output cumulatively across all tables#1880
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 1bba0ab | Commit Preview URL Branch Preview URL |
Jun 05 2026, 01:14 AM |
There was a problem hiding this comment.
Pull request overview
This PR addresses DeepSec #1869 by ensuring the SQLite .dump dot-command enforces max_output_bytes during output construction (cumulatively across all tables), preventing unbounded growth of the dump output buffer before the global output cap is applied.
Changes:
- Passes the remaining output budget into dot-command dispatch so
.dumpcan enforce the cap cumulatively across schema + data. - Adds
DotError::OutputCapand abounded_append()helper to stop.dumpconstruction as soon as it would exceed the budget. - Adds regression tests validating
.dumpstops mid-construction under a tight cap and still succeeds for a small empty DB.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| crates/bashkit/src/builtins/sqlite/mod.rs | Computes remaining output budget and passes it into dot-command dispatch so .dump can enforce a cumulative cap. |
| crates/bashkit/src/builtins/sqlite/dot_commands.rs | Implements bounded .dump construction via bounded_append(), adds OutputCap error variant, and adds tests for the new behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+55
to
+56
| #[error("sqlite output exceeds byte cap ({0} > {1})")] | ||
| OutputCap(usize, usize), |
Comment on lines
+288
to
+290
| /// Append `chunk` to `buf`, returning `Err(OutputCap)` if doing so would | ||
| /// exceed `max`. This enforces the output budget *during* construction so | ||
| /// memory never grows beyond the cap even for large multi-table dumps. |
42c9559 to
1694110
Compare
Pass the remaining output budget into dump() via dispatch(), and enforce it during construction with bounded_append(). Previously each per-table SELECT was bounded by max_result_bytes, but cumulative dump output could grow unboundedly before the caller applied push_stdout_bounded. An attacker controlling many tables/rows could exhaust memory. Changes: - DotError::OutputCap variant for clean Display-formatted cap errors - bounded_append() helper: checks cumulative budget before each push - dispatch() gains max_output_bytes param; run_statements passes remaining - New unit tests: dump_respects_output_cap, dump_empty_db_under_cap - New integration test: dump_output_cap_enforced_across_multiple_tables - THREAT[TM-DOS-091] annotation at mitigation point - Updated specs/threat-model.md (TM-DOS-091) and specs/sqlite-builtin.md (TM-SQL-013) Closes #1869
1694110 to
1bba0ab
Compare
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.
Summary
.dumpdot-command previously built the full output string before the caller appliedmax_output_bytes, allowing memory to grow unboundedly across many tables (DeepSec [DeepSec][MEDIUM] SQLite .dump builds full output before enforcing output cap #1869)max_output_bytesparameter todispatch()anddump(), enforced via abounded_append()helper that checks the cumulative budget after each schema line and each row INSERTDotError::OutputCapvariant for clean, Display-formatted error messages (no debug shapes)run_statementsnow passesremaining = max_output_bytes - stdout.len()todispatch()so the cap is applied against overall invocation outputTest plan
dump_respects_output_cap— verifies.dumpreturnsDotError::OutputCapmid-construction when a tight budget is set across multiple tables with rowsdump_empty_db_under_cap— verifies a small dump still succeeds within a reasonable budgetcargo test --features sqlite -p bashkit --lib)cargo build --features sqlite -p bashkitclean build{:?}debug format strings in builtin code (error messages use Display)Closes #1869