security: NixOS systemd hardening regression — restore baseline isolation #51

Open
opened 2026-06-13 22:03:02 +00:00 by padreug · 0 comments
Owner

Migrated from aiolabs/lamassu-next#51 — opened by @padreug on 2026-05-26.\n\n## Problem

flake.nix:204-223 (the installed config) force-disables every hardening flag the bitspire-atm.nix module sets sanely:

NoNewPrivileges = mkForce false
ProtectSystem   = mkForce false
ProtectHome     = mkForce false
PrivateTmp      = mkForce false
DevicePolicy    = mkForce "auto"

Combined with the Electron renderer running --no-sandbox (also in flake.nix), if the renderer is ever compromised (XSS via a dependency, Vue templating XSS, etc.) there is currently zero filesystem isolation between renderer and the rest of the system. The bitspire user is still unprivileged, but post-compromise the attacker can read /var/lib/bitspire/.env (the nsec stopgap), write anywhere the bitspire user has perms, and access all /dev/tty* and /dev/video*.

The override comment cites "Electron sandbox needs unprivileged user namespaces" — true in general, but worth investigating whether:

  1. Chromium's --sandbox flag (the renderer sandbox, distinct from systemd's NoNewPrivileges) can be enabled on top of more conservative systemd flags.
  2. SystemCallFilter, CapabilityBoundingSet, RestrictAddressFamilies, and read-only /usr can be combined with the unprivileged-user-namespace requirement.
  3. We can keep NoNewPrivileges=true while still allowing the Chromium sandbox by setting kernel.unprivileged_userns_clone=1 and running the renderer with appropriate capability sets.

Goal

Find a configuration that satisfies BOTH:

  • Electron's renderer sandbox works (currently disabled with --no-sandbox).
  • Compromised renderer cannot read /var/lib/bitspire/.env, write outside its sandbox, or escalate.

If a full solution isn't reachable, document the trade-off explicitly and add compensating controls:

  • Read-only root filesystem
  • Strict nftables egress (only relay + LNbits HTTP)
  • Reduced CapabilityBoundingSet
  • AppArmor / SELinux profile for the Electron binary

Acceptance

  • Renderer sandbox enabled (no --no-sandbox) OR documented why infeasible.
  • At least ProtectSystem=strict + ProtectHome=true + PrivateTmp=true restored.
  • NoNewPrivileges=true restored unless a documented blocker is found.
  • /var/lib/bitspire/.env unreadable from the renderer process namespace.
  • Existing functionality (hardware HAL, dispense, validator, camera) unchanged.

References

  • Cross-codebase review 2026-05-26, security audit agent finding #1 (severity MEDIUM, but blocks production-grade rating).
  • Related: aiolabs/lnbits#18 (bunker) will eventually move the nsec off-disk entirely; this issue is the defence-in-depth that matters until then.
  • Estimated effort: 8h investigation + patch + test.
> _Migrated from [aiolabs/lamassu-next#51](https://git.atitlan.io/aiolabs/lamassu-next/issues/51) — opened by @padreug on 2026-05-26._\n\n## Problem `flake.nix:204-223` (the installed config) force-disables every hardening flag the `bitspire-atm.nix` module sets sanely: ```nix NoNewPrivileges = mkForce false ProtectSystem = mkForce false ProtectHome = mkForce false PrivateTmp = mkForce false DevicePolicy = mkForce "auto" ``` Combined with the Electron renderer running `--no-sandbox` (also in flake.nix), if the renderer is ever compromised (XSS via a dependency, Vue templating XSS, etc.) **there is currently zero filesystem isolation** between renderer and the rest of the system. The `bitspire` user is still unprivileged, but post-compromise the attacker can read `/var/lib/bitspire/.env` (the nsec stopgap), write anywhere the bitspire user has perms, and access all `/dev/tty*` and `/dev/video*`. The override comment cites *"Electron sandbox needs unprivileged user namespaces"* — true in general, but worth investigating whether: 1. Chromium's `--sandbox` flag (the *renderer* sandbox, distinct from systemd's `NoNewPrivileges`) can be enabled on top of more conservative systemd flags. 2. `SystemCallFilter`, `CapabilityBoundingSet`, `RestrictAddressFamilies`, and read-only `/usr` can be combined with the unprivileged-user-namespace requirement. 3. We can keep `NoNewPrivileges=true` while still allowing the Chromium sandbox by setting `kernel.unprivileged_userns_clone=1` and running the renderer with appropriate capability sets. ## Goal Find a configuration that satisfies BOTH: - Electron's renderer sandbox works (currently disabled with `--no-sandbox`). - Compromised renderer cannot read `/var/lib/bitspire/.env`, write outside its sandbox, or escalate. If a full solution isn't reachable, document the trade-off explicitly and add compensating controls: - Read-only root filesystem - Strict `nftables` egress (only relay + LNbits HTTP) - Reduced `CapabilityBoundingSet` - AppArmor / SELinux profile for the Electron binary ## Acceptance - [ ] Renderer sandbox enabled (no `--no-sandbox`) OR documented why infeasible. - [ ] At least `ProtectSystem=strict` + `ProtectHome=true` + `PrivateTmp=true` restored. - [ ] `NoNewPrivileges=true` restored unless a documented blocker is found. - [ ] `/var/lib/bitspire/.env` unreadable from the renderer process namespace. - [ ] Existing functionality (hardware HAL, dispense, validator, camera) unchanged. ## References - Cross-codebase review 2026-05-26, security audit agent finding #1 (severity MEDIUM, but blocks production-grade rating). - Related: `aiolabs/lnbits#18` (bunker) will eventually move the nsec off-disk entirely; this issue is the defence-in-depth that matters until then. - Estimated effort: 8h investigation + patch + test.
Sign in to join this conversation.
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
aiolabs/bitspire#51
No description provided.