Skip to content

Harden daemon: fail closed on symlinked COVEN_HOME and non-socket socket path#144

Merged
BunsDev merged 1 commit into
OpenCoven:mainfrom
maplesyzzurp:fix/daemon-socket-hardening
May 30, 2026
Merged

Harden daemon: fail closed on symlinked COVEN_HOME and non-socket socket path#144
BunsDev merged 1 commit into
OpenCoven:mainfrom
maplesyzzurp:fix/daemon-socket-hardening

Conversation

@maplesyzzurp
Copy link
Copy Markdown
Contributor

Summary

Closes the two still-open docs/AUTH.md "Current hardening gap" fail-closed checks in crates/coven-cli/src/daemon.rs:

  • ensure_private_coven_home now refuses a COVEN_HOME that is a symlink, so following it cannot redirect daemon state (socket, status, SQLite ledger) outside the trusted directory.
  • bind_api_socket now inspects the socket path with symlink_metadata and refuses a symlink or any non-socket file, instead of calling remove_file on whatever happens to be there. Only a genuine stale socket is replaced.

Why

docs/AUTH.md lists these exact conditions under "Before broad distribution, Rust should fail closed when ... COVEN_HOME resolves through a symlink ... an existing socket path is a symlink or non-socket file." The TypeScript plugin already validates the socket trust anchor; this brings the Rust daemon in line. The euid-ownership check from the same list is intentionally left out of this PR because it needs a libc::geteuid dependency.

Changes

  • ensure_private_coven_home: symlink_metadata guard; bail when the home is a symlink.
  • bind_api_socket: symlink_metadata + FileTypeExt::is_socket; bail on a symlink or non-socket; only remove_file a genuine stale socket; treat NotFound as fresh.
  • 3 new #[cfg(unix)] tests (symlinked home, symlinked socket path with target-not-deleted assertion, non-socket file at the socket path).

std-only — no new dependencies, no unsafe, Unix-gated.

Verification

cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, and cargo test --workspace --locked all green on Linux: 696 unit + 4 smoke tests pass, including the 3 new ones, no regressions.

Tracked by #142.


Note: I see PRs are frozen until July per CONTRIBUTING — opening this for visibility since it is a small, isolated security hardening that closes a documented gap. Completely fine to close or hold it until the window reopens; the branch will keep.

The daemon created COVEN_HOME and bound coven.sock without checking
whether either path was a symlink, or (for the socket) a non-socket
file it would blindly remove. docs/AUTH.md lists exactly these as the
remaining fail-closed hardening items before broad distribution.

- ensure_private_coven_home now refuses a COVEN_HOME that is a symlink,
  so following it cannot redirect daemon state (socket, status, SQLite
  ledger) outside the trusted directory.
- bind_api_socket now inspects the socket path with symlink_metadata
  and refuses a symlink or any non-socket file, instead of calling
  remove_file on whatever happens to be there; only a genuine stale
  socket is replaced.

std-only, no new dependencies, no unsafe; Unix-gated. Adds three
cfg(unix) tests. Full workspace suite green: fmt --check, clippy
--all-targets -D warnings, cargo test --workspace --locked.

The euid-ownership fail-closed check from AUTH.md is left as a
follow-up; it needs a libc geteuid dependency.

Refs: docs/AUTH.md "Current hardening gap"
@maplesyzzurp
Copy link
Copy Markdown
Contributor Author

/Lock-in
Shoutout to C#aude 4.8 M8

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