Skip to content

fix(store): harden DB open against path injection (CodeQL #15) - #147

Merged
joshuaboys merged 1 commit into
mainfrom
cursor/fix-codeql-path-injection-0cfe
Sep 7, 2026
Merged

joshuaboys merged 1 commit into
mainfrom
cursor/fix-codeql-path-injection-0cfe

Conversation

@joshuaboys

Copy link
Copy Markdown
Contributor

Closes CodeQL alert #15 (rust/path-injection, high): uncontrolled data used in path expression at crates/kindling-store/src/db.rs create_dir_all.

Investigation

This is a real sink (create_dir_all + SQLite open on a caller-supplied path) with a narrow threat model, not a classic remote traversal of X-Kindling-Project.

Source Reaches open_database as Risk
Daemon X-Kindling-Project project_db_path(home, root) → home/projects/<12-hex SHA-256>/kindling.db Already confined. The header is never a path component.
CLI --db / KINDLING_DB_PATH Raw filesystem path (intended local config) Operator can point the DB anywhere they can write. Accepted for a local-first tool.
Public SqliteKindlingStore::open / KindlingService::open Same raw path Library callers must not pass untrusted strings.

Two issues were not accepted residual:

  1. SQLite URI injection. Readonly opens set SQLITE_OPEN_URI, and OpenFlags::default() includes URI as well. A path like file:/tmp/x?mode=rwc could be reinterpreted as a URI instead of a file path.
  2. create_dir_all before validation. The CLI (open_service, init --skip-db) mkdir'd parents from the raw path, so a .. value could create directories even if open later failed.

Confining every open to ~/.kindling would break legitimate --db, KINDLING_DB_PATH, and temp-dir tests. The store therefore still accepts any local filesystem location without .. / URI / NUL.

Fix

  • validate_db_path runs before mkdir or SQLite open. Rejects empty / non-UTF-8 / NUL, SQLite special names (file:…, :memory:, :temp:), and .. (the CodeQL DotDotCheck sanitizer guard). The path used at the sink is reconstructed from the checked string.
  • Open flags drop SQLITE_OPEN_URI and add SQLITE_OPEN_NOFOLLOW.
  • project_db_path documents and debug_asserts that project_id is a single 12-hex component.
  • CLI no longer mkdir's before the store validates; init --skip-db validates first.

Residual

An operator can still open/create a DB at any path that does not contain .. (e.g. --db /var/tmp/kindling.db). That is intentional local configuration, not remote input. Daemon project routing remains hash-confined under kindling_home.

Tests

  • Store: nested parents still created; .., URI/special names, empty, and NUL rejected.
  • Paths: traversal-like project_root values stay under kindling_home as projects/<hex>/kindling.db.
Open in Web Open in Cursor 

Validate DB paths before create_dir_all/SQLite open (no '..', NUL, or
URI names), drop SQLITE_OPEN_URI, and confine project ids to a hashed
hex component. Fixes CodeQL rust/path-injection alert #15.

Co-authored-by: Josh Boys <josh@arkahna.io>
@joshuaboys
joshuaboys marked this pull request as ready for review September 7, 2026 05:18
@joshuaboys
joshuaboys merged commit 1da9204 into main Sep 7, 2026
26 checks passed
@joshuaboys
joshuaboys deleted the cursor/fix-codeql-path-injection-0cfe branch September 7, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants