Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@
**Vulnerability:** A script created temporary files at predictable paths (`/tmp/wiki_claude_{session_id}.txt`) allowing potential local attackers to execute a symlink attack or view sensitive session content.
**Learning:** Hardcoded predictable temporary file paths, especially those derived from predictable elements like session_ids, expose local file operations to race conditions.
**Prevention:** Always use secure temporary file creation APIs like Python's `tempfile.NamedTemporaryFile` or Bash's `mktemp`, and pass the dynamically generated file path between components rather than assuming predictable names.

## 2025-02-27 - SQL Injection in Daily Digest script
**Vulnerability:** SQL injection vulnerabilities were present in `bin/wiki-daily-digest` where externally supplied variables (`$session_id` and `$date`) were directly interpolated into `sqlite3` string queries without proper sanitization.
**Learning:** Internal tools that process externally populated databases (like SQLite) are still susceptible to SQL injection if string interpolation is used instead of parameterization or strict sanitization.
**Prevention:** Always use safe parameter expansion (e.g. `${var//\'/\'\'}`) when interpolating Bash variables into SQLite queries to correctly escape single quotes, even in scripts not directly facing the public network.
6 changes: 3 additions & 3 deletions bin/wiki-daily-digest
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ _extract_session_content() {
SELECT json_extract(p.data, '$.text')
FROM part p
JOIN message m ON p.message_id = m.id
WHERE m.session_id = '$session_id'
WHERE m.session_id = '${session_id//\'/\'\'}'
AND json_extract(m.data, '$.role') = 'assistant'
AND json_extract(p.data, '$.type') = 'text'
AND length(json_extract(p.data, '$.text')) > 20
Expand All @@ -162,7 +162,7 @@ SELECT
s.created_at,
s.updated_at
FROM sessions s
WHERE date(s.updated_at) = '$date'
WHERE date(s.updated_at) = '${date//\'/\'\'}'
ORDER BY s.created_at ASC;" 2>/dev/null
}

Expand All @@ -175,7 +175,7 @@ _extract_goose_content() {
content="$(sqlite3 "$GOOSE_DB" "
SELECT substr(m.content_json, 1, 2000)
FROM messages m
WHERE m.session_id = '$session_id'
WHERE m.session_id = '${session_id//\'/\'\'}'
AND m.role = 'assistant'
ORDER BY m.created_at ASC;" 2>/dev/null | python3 -c "
import sys, json
Expand Down
Loading