Skip to content

Move debug log defaults out of /tmp and reject symlinks - #38

Merged
randileeharper merged 1 commit into
mainfrom
fix/symlink-safe-debug-paths-23
Jun 29, 2026
Merged

Move debug log defaults out of /tmp and reject symlinks#38
randileeharper merged 1 commit into
mainfrom
fix/symlink-safe-debug-paths-23

Conversation

@randileeharper

Copy link
Copy Markdown
Owner

Summary

The default debug_log_path and resolver_debug_log_path lived in /tmp (world-writable on shared hosts). An attacker who pre-creates a symlink at /tmp/historian-debug.log → e.g. ~/.ssh/authorized_keys could trick Historian, with debug mode on, into overwriting an arbitrary file, because _prepare_private_file opened with O_CREAT and no O_NOFOLLOW/O_EXCL.

This applies the issue's recommended Option 1 plus Option 2 as defense-in-depth:

  • Move defaults under the XDG data dir (~/.local/share/historian/), which is not world-writable — matching how database_path already works. Updated in config.py, config.example.json, and docs/debugging.md.
  • Add O_NOFOLLOW to _prepare_private_file so a symlinked target is rejected at open time rather than followed, even when a user sets a custom path.

New tests verify the defaults no longer point at /tmp and that a symlink target is refused (and the pointed-at file left untouched).

Closes #23.

Test commands run

uv run pytest -q
uv run python -m compileall historian tests

All 70 tests pass; compile check clean.

The default debug_log_path and resolver_debug_log_path were in /tmp,
which is world-writable on shared hosts. An attacker who pre-creates a
symlink at /tmp/historian-debug.log pointing at e.g. an authorized_keys
file could trick Historian (with debug mode on) into overwriting an
arbitrary file, because _prepare_private_file opened with O_CREAT and no
O_NOFOLLOW/O_EXCL.

Two defenses, per the issue:
- Move defaults under the XDG data dir (~/.local/share/historian/),
  which is not world-writable, matching how database_path already works.
- Add O_NOFOLLOW to _prepare_private_file so a symlinked target is
  rejected at open time rather than followed, even for custom paths.

Updates config.py, config.example.json, and docs/debugging.md. Adds tests
for the new defaults and symlink rejection.
@randileeharper
randileeharper merged commit 184b67e into main Jun 29, 2026
1 check passed
@randileeharper
randileeharper deleted the fix/symlink-safe-debug-paths-23 branch June 29, 2026 20:19
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.

Default debug log paths in /tmp are vulnerable to symlink attacks

1 participant