vault provision: canonicalize + enforce allowed-root containment on the jail target #92

Closed
opened 2026-06-20 06:26:51 +02:00 by clawdie · 0 comments
Owner

Builds on #91

PR #91 added a registered-vs-spawned jail-root check before vault provisioning, but it's a string-equality compare (trim_trailing_slash(stored) != trim_trailing_slash(spawned)), not canonicalization. It catches "spawned jail ≠ registered jail," but not:

  • a path containing .. or a symlink (both sides can be string-equal yet resolve elsewhere)
  • a registered/spawned root that points outside the allowed Bastille jails root

Fix

Before writing the .env, canonicalize the target (std::fs::canonicalize, resolving symlinks/..) and assert it is contained under the allowed root, e.g. matches /usr/local/bastille/jails/<name>/root. Refuse (warn + skip, fail-soft) otherwise.

Pairs with the UNIQUE(jail_root_path) constraint tracked separately — together they make the root mapping unique and bounded.

Acceptance

A tenant whose registered/spawned root contains .., a symlink, or resolves outside /usr/local/bastille/jails/.../root is refused — no .env written.

Security invariant: see docs/HIVE-ONBOARDING.md (layered-soul). Related: #91.

🤖 Generated with Claude Code

## Builds on #91 PR #91 added a registered-vs-spawned jail-root check before vault provisioning, but it's a **string-equality** compare (`trim_trailing_slash(stored) != trim_trailing_slash(spawned)`), not canonicalization. It catches "spawned jail ≠ registered jail," but **not**: - a path containing `..` or a symlink (both sides can be string-equal yet resolve elsewhere) - a registered/spawned root that points **outside** the allowed Bastille jails root ## Fix Before writing the `.env`, **canonicalize** the target (`std::fs::canonicalize`, resolving symlinks/`..`) and assert it is **contained under** the allowed root, e.g. matches `/usr/local/bastille/jails/<name>/root`. Refuse (warn + skip, fail-soft) otherwise. Pairs with the `UNIQUE(jail_root_path)` constraint tracked separately — together they make the root mapping unique *and* bounded. ## Acceptance A tenant whose registered/spawned root contains `..`, a symlink, or resolves outside `/usr/local/bastille/jails/.../root` is refused — no `.env` written. Security invariant: see docs/HIVE-ONBOARDING.md (layered-soul). Related: #91. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
clawdie added the
hardening
label 2026-06-20 06:38:05 +02:00
Sign in to join this conversation.
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: clawdie/colibri#92
No description provided.