feat: socket authentication for daemon (audit H1 fix) #17

Open
doxios wants to merge 1 commit from doxios/avault:feat/socket-auth into main
First-time contributor

Summary

Adds token-based authentication to the Unix socket daemon, addressing finding H1 from the security audit (#16).

Problem

Previously, any process running as the same user could connect to the avault Unix socket and issue commands (get, set, shutdown). This undermined the vault's purpose of isolating secrets from the agent — the agent process (same user) could just talk to the socket directly.

Solution

Token-based socket authentication:

  1. On startup, daemon generates a random 32-byte (64 hex char) token via secrets.token_hex(32)
  2. Token written atomically to $XDG_RUNTIME_DIR/avault.token (chmod 0600)
  3. Every socket request must include {"token": "<hex>"} field
  4. Daemon verifies with secrets.compare_digest() (constant-time, no timing attacks)
  5. Token stripped from request before reaching handle_request() (no leakage to business logic)
  6. Token file cleaned up on daemon shutdown
  7. CLI (daemon_request()) automatically reads token from file and injects into requests

Access Control

The token file can be further restricted via:

  • Filesystem ACLs (setfacl -m u:cobot:r /run/user/1000/avault.token)
  • Group permissions (run daemon as different user, share token via group)
  • Separate user for daemon vs agent (long-term recommendation)

Changes

File Changes
scripts/avault.py +89 lines: token generation, write/read/cleanup helpers, auth check in handle_client(), token injection in daemon_request(), doctor check
scripts/test_avault.py +174 lines: 11 new tests across TestSocketAuth and TestAuthTokenFileOps
.gitignore New: ignore __pycache__/

Tests

11 new tests, all passing:

  • TestSocketAuth::test_valid_token_allows_request
  • TestSocketAuth::test_missing_token_rejected
  • TestSocketAuth::test_wrong_token_rejected
  • TestSocketAuth::test_no_auth_when_token_not_set
  • TestSocketAuth::test_token_stripped_before_handle_request
  • TestAuthTokenFileOps::test_write_and_read_token
  • TestAuthTokenFileOps::test_read_missing_token
  • TestAuthTokenFileOps::test_cleanup_token
  • TestAuthTokenFileOps::test_cleanup_missing_token_no_error
  • TestAuthTokenFileOps::test_generate_auth_token_length
  • TestAuthTokenFileOps::test_generate_auth_token_unique

All 69 existing tests continue to pass (1 pre-existing QR test failure, unrelated).

Backward Compatibility

  • If auth_token is None (daemon started without token generation, e.g., old code), auth is skipped — requests pass through as before
  • If token file is missing, daemon_request() sends request without token — daemon will reject it with a clear error message pointing to the token file location
  • The AVAULT_TOKEN env var overrides the token file path (same pattern as AVAULT_SOCKET)

Refs

  • Fixes #16 (H1: No Authentication on Unix Socket)
  • Requested by @webdiverblue

PR by Doxios 🦊 — security patch from audit findings

## Summary Adds token-based authentication to the Unix socket daemon, addressing finding **H1** from the [security audit (#16)](https://forgejo.tail593e12.ts.net/nazim/avault/issues/16). ## Problem Previously, any process running as the same user could connect to the avault Unix socket and issue commands (`get`, `set`, `shutdown`). This undermined the vault's purpose of isolating secrets from the agent — the agent process (same user) could just talk to the socket directly. ## Solution **Token-based socket authentication:** 1. On startup, daemon generates a random 32-byte (64 hex char) token via `secrets.token_hex(32)` 2. Token written atomically to `$XDG_RUNTIME_DIR/avault.token` (chmod `0600`) 3. Every socket request must include `{"token": "<hex>"}` field 4. Daemon verifies with `secrets.compare_digest()` (constant-time, no timing attacks) 5. Token stripped from request before reaching `handle_request()` (no leakage to business logic) 6. Token file cleaned up on daemon shutdown 7. CLI (`daemon_request()`) automatically reads token from file and injects into requests ### Access Control The token file can be further restricted via: - Filesystem ACLs (`setfacl -m u:cobot:r /run/user/1000/avault.token`) - Group permissions (run daemon as different user, share token via group) - Separate user for daemon vs agent (long-term recommendation) ## Changes | File | Changes | |------|---------| | `scripts/avault.py` | +89 lines: token generation, write/read/cleanup helpers, auth check in `handle_client()`, token injection in `daemon_request()`, doctor check | | `scripts/test_avault.py` | +174 lines: 11 new tests across `TestSocketAuth` and `TestAuthTokenFileOps` | | `.gitignore` | New: ignore `__pycache__/` | ## Tests **11 new tests, all passing:** - `TestSocketAuth::test_valid_token_allows_request` ✅ - `TestSocketAuth::test_missing_token_rejected` ✅ - `TestSocketAuth::test_wrong_token_rejected` ✅ - `TestSocketAuth::test_no_auth_when_token_not_set` ✅ - `TestSocketAuth::test_token_stripped_before_handle_request` ✅ - `TestAuthTokenFileOps::test_write_and_read_token` ✅ - `TestAuthTokenFileOps::test_read_missing_token` ✅ - `TestAuthTokenFileOps::test_cleanup_token` ✅ - `TestAuthTokenFileOps::test_cleanup_missing_token_no_error` ✅ - `TestAuthTokenFileOps::test_generate_auth_token_length` ✅ - `TestAuthTokenFileOps::test_generate_auth_token_unique` ✅ All 69 existing tests continue to pass (1 pre-existing QR test failure, unrelated). ## Backward Compatibility - **If `auth_token` is `None`** (daemon started without token generation, e.g., old code), auth is skipped — requests pass through as before - **If token file is missing**, `daemon_request()` sends request without token — daemon will reject it with a clear error message pointing to the token file location - The `AVAULT_TOKEN` env var overrides the token file path (same pattern as `AVAULT_SOCKET`) ## Refs - Fixes #16 (H1: No Authentication on Unix Socket) - Requested by @webdiverblue --- *PR by Doxios 🦊 — security patch from audit findings*
feat: socket authentication for daemon (H1 fix)
Some checks failed
Tests / test (3.11) (pull_request) Has been cancelled
Tests / test (3.12) (pull_request) Has been cancelled
Tests / test (3.13) (pull_request) Has been cancelled
2ab48efca7
Add token-based authentication to the Unix socket daemon to prevent
unauthorized same-user processes from accessing secrets.

How it works:
- Daemon generates a random 32-byte token on startup
- Token written to $XDG_RUNTIME_DIR/avault.token (chmod 0600)
- Every socket request must include {"token": "<hex>"} field
- Token verified with constant-time comparison (secrets.compare_digest)
- Token file cleaned up on daemon shutdown
- CLI automatically reads token from file and injects into requests

This addresses audit finding H1: any same-user process could previously
connect to the socket and read/modify all secrets. Now only processes
that can read the token file are authorized.

The token file can be further restricted via filesystem ACLs to limit
which specific processes (e.g., only the Cobot agent) can access it.

Doctor command updated with auth_token health check.
11 new tests added (all passing).

Ref: nazim/avault#16 (security audit)
Some checks failed
Tests / test (3.11) (pull_request) Has been cancelled
Tests / test (3.12) (pull_request) Has been cancelled
Tests / test (3.13) (pull_request) Has been cancelled
This pull request can be merged automatically.
Some workflows are waiting to be reviewed.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u feat/socket-auth:doxios-feat/socket-auth
git switch doxios-feat/socket-auth

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff doxios-feat/socket-auth
git switch doxios-feat/socket-auth
git rebase main
git switch main
git merge --ff-only doxios-feat/socket-auth
git switch doxios-feat/socket-auth
git rebase main
git switch main
git merge --no-ff doxios-feat/socket-auth
git switch main
git merge --squash doxios-feat/socket-auth
git switch main
git merge --ff-only doxios-feat/socket-auth
git switch main
git merge doxios-feat/socket-auth
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nazim/avault!17
No description provided.