Skip to content

fix(security): prevent SQL injection via apostrophe in ATTACH DATABASE path (issue #324)#348

Merged
xlabtg merged 5 commits intoxlabtg:mainfrom
konard:issue-324-0f0e13c09f19
Apr 23, 2026
Merged

fix(security): prevent SQL injection via apostrophe in ATTACH DATABASE path (issue #324)#348
xlabtg merged 5 commits intoxlabtg:mainfrom
konard:issue-324-0f0e13c09f19

Conversation

@konard
Copy link
Copy Markdown

@konard konard commented Apr 23, 2026

Summary

Fixes #324AUDIT-FULL-M4: ATTACH DATABASE interpolated an unescaped MAIN_DB_PATH, allowing a single quote in TELETON_ROOT (legal on POSIX, e.g. /home/o'brien/) to break out of the SQL string literal and inject arbitrary SQL.

Changes

src/utils/module-db.ts — escape before interpolation

// Before (vulnerable)
moduleDb.exec(`ATTACH DATABASE '${MAIN_DB_PATH}' AS main_db`);

// After (safe)
const escapedPath = MAIN_DB_PATH.replace(/'/g, "''");
moduleDb.exec(`ATTACH DATABASE '${escapedPath}' AS main_db`);

src/workspace/paths.ts — validate TELETON_ROOT at startup
Added a startup check that throws immediately if TELETON_ROOT contains shell metacharacters (` $\!|;&<>*?{}()[]"), so every downstream consumer (including module-db.ts) gets a pre-validated value.

src/utils/__tests__/module-db.test.ts — regression tests

  • Confirms escaped path with apostrophe is syntactically valid SQL (no throw)
  • Confirms an unescaped apostrophe in ATTACH DATABASE does throw a syntax error (proof of the original bug)
  • Confirms migrateFromMainDb returns 0 when main DB is absent (happy path)
  • Confirms the metacharacter regex rejects `, $, ;, | and accepts plain paths and paths with apostrophes

How to reproduce the original bug

import Database from "better-sqlite3";
const db = new Database(":memory:");
const badPath = "/home/o'brien/.teleton/memory.db";
db.exec(`ATTACH DATABASE '${badPath}' AS main_db`); // SqliteError: unrecognized token: "brien"

Acceptance criteria

  • Path is escaped before substitution in ATTACH DATABASE
  • TELETON_ROOT is validated at startup against shell metacharacters
  • Regression test: escaped path with 'ATTACH succeeds (no injection)
  • Regression test: unescaped ' in path → SQL syntax error (demonstrating the original vulnerability)
  • Regression test: shell metacharacters in TELETON_ROOT are rejected at startup

Fixes #324

Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: xlabtg#324
…e in path

- Escape single quotes in MAIN_DB_PATH before interpolation in the
  ATTACH DATABASE statement in migrateFromMainDb() (module-db.ts:109)
- Validate TELETON_ROOT at startup to reject shell metacharacters
  (`$\!|;&<>*?{}()[]\") that could be dangerous in subprocess or SQL
  contexts (paths.ts)
- Add regression tests: confirm escaped path is syntactically valid SQL,
  confirm an unescaped apostrophe does break SQL, confirm the unsafe
  character regex catches metacharacters and allows apostrophes/normal paths

Fixes xlabtg#324
@konard konard changed the title [WIP] [AUDIT-FULL-M4] ATTACH DATABASE interpolates an unescaped TELETON_ROOT; apostrophe in home dir → SQL injection fix(security): prevent SQL injection via apostrophe in ATTACH DATABASE path (issue #324) Apr 23, 2026
@konard konard marked this pull request as ready for review April 23, 2026 05:00
konard added 2 commits April 23, 2026 05:03
… path

ATTACH DATABASE fails with 'unable to open database' when the parent
directory does not exist. Create the o'brien temp directory explicitly
so SQLite can actually write the file, proving escaping works end-to-end.
…or' prefix

SQLite throws with just the bare message text (e.g. 'near "brien": syntax
error'), not the class name. Use .toThrow() without a pattern to match any
thrown error from the unescaped apostrophe test case.
@konard
Copy link
Copy Markdown
Author

konard commented Apr 23, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost: $2.461840

📊 Context and tokens usage:

  • 93.0K / 1M (9%) input tokens, 18.7K / 64K (29%) output tokens

Total: (82.5K + 6.2M cached) input tokens, 18.7K output tokens, $2.461840 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: sonnet
  • Model: Claude Sonnet 4.6 (claude-sonnet-4-6)

📎 Log file uploaded as Gist (2357KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Copy Markdown
Author

konard commented Apr 23, 2026

✅ Ready to merge

This pull request is now ready to be merged:

  • All CI checks have passed
  • No merge conflicts
  • No pending changes

Monitored by hive-mind with --auto-restart-until-mergeable flag

@xlabtg xlabtg merged commit b86d18a into xlabtg:main Apr 23, 2026
18 checks passed
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.

[AUDIT-FULL-M4] ATTACH DATABASE interpolates an unescaped TELETON_ROOT; apostrophe in home dir → SQL injection

2 participants