Skip to content

fix(security): bound ShadowSentinel hot-path DB reads with an explicit timeout - #6293

Merged
bug-ops merged 1 commit into
mainfrom
fix/6269-shadow-sentinel-db-timeout
Jul 14, 2026
Merged

fix(security): bound ShadowSentinel hot-path DB reads with an explicit timeout#6293
bug-ops merged 1 commit into
mainfrom
fix/6269-shadow-sentinel-db-timeout

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • ShadowSentinel::check_tool_call awaited two DB reads (get_trajectory, get_tool_history) on the pre-tool-dispatch hot path shared by every high-risk tool call (Shell/FileWrite/ExfilCapable/McpUnclassified) with no timeout — a stalled DB connection (e.g. a slow/unresponsive Postgres backend) could block dispatch indefinitely.
  • Both reads are now wrapped in tokio::time::timeout, bounded by the existing probe_timeout_ms.min(2000) config value (no new config field). A timeout logs a warning and falls back to the same empty/partial result the pre-existing DB-error branch already produced — fail-open, matching ShadowSentinel's documented defence-in-depth contract.
  • Extracted the trajectory + cross-session-history loading logic into a new private load_probe_context method to stay under clippy::too_many_lines after adding the timeout wrapping; behavior-preserving, verified line-by-line against the pre-fix code.
  • Corrected a doc comment to state the true additive worst-case latency (2 * probe_timeout_ms.min(2000) + probe_timeout_ms, ~6s at defaults) rather than a misleading single shared ~2s bound.

Closes #6269

Test plan

  • New regression test check_tool_call_falls_open_when_both_db_reads_stall: forces a genuine timeout via real SQLite pool exhaustion (max_connections(1) on :memory:), verifies both DB reads independently hit their timeout branch (both distinct warn logs fire) and check_tool_call still resolves fail-open with an empty trajectory despite real seeded data existing.
  • cargo +nightly fmt --check
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins — full suite green
  • Rustdoc gate (RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links") — clean, new intra-doc link resolves
  • gitleaks protect --staged — no leaks
  • Adversarial critique + code review completed, both approved

@github-actions github-actions Bot added bug Something isn't working size/L Large PR (201-500 lines) documentation Improvements or additions to documentation rust Rust code changes core zeph-core crate labels Jul 14, 2026
@bug-ops
bug-ops enabled auto-merge (squash) July 14, 2026 18:51
@bug-ops
bug-ops force-pushed the fix/6269-shadow-sentinel-db-timeout branch 2 times, most recently from 973b671 to e214434 Compare July 14, 2026 19:05
…t timeout

check_tool_call awaited get_trajectory and get_tool_history with no
timeout on the pre-tool-dispatch hot path shared by every high-risk
tool call. A stalled DB connection (e.g. a slow Postgres backend)
could block dispatch of every Shell/FileWrite/ExfilCapable/
McpUnclassified tool call for the session.

Both reads are now wrapped in tokio::time::timeout, bounded by the
existing probe_timeout_ms.min(2000) config value. A timeout falls
back to the same empty/partial result the pre-existing DB-error
branch already produced, matching ShadowSentinel's documented
fail-open contract.

Closes #6269
@bug-ops
bug-ops force-pushed the fix/6269-shadow-sentinel-db-timeout branch from e214434 to 5bf7e9f Compare July 14, 2026 19:15
@bug-ops
bug-ops merged commit cac177c into main Jul 14, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6269-shadow-sentinel-db-timeout branch July 14, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working core zeph-core crate documentation Improvements or additions to documentation rust Rust code changes size/L Large PR (201-500 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

shadow_sentinel: check_tool_call DB reads have no timeout on hot tool-dispatch path

1 participant