veilor-os/docs/THREAT-MODEL.md
s8n-ru e4b6516f1c
Some checks failed
Lint / Kickstart syntax (pull_request) Failing after 0s
Lint / Shell scripts (pull_request) Failing after 0s
Lint / No personal/onyx leaks (pull_request) Failing after 0s
sec: polish THREAT-MODEL.md for v0.7 public launch
Status flipped Draft → Final.

In-scope rows now cite specific config files / settings (auditable
from clean checkout):
  - LUKS2 params from kickstart/veilor-os.ks
  - sysctl knobs file path
  - USBGuard policy mode + rule type
  - sshd_config drop-in path + every directive
  - auditd rule path + watched paths
  - chrony NTS endpoints
  - systemd-resolved DoT settings
  - bootloader kernel args (lockdown, slab_nomerge, init_on_alloc/free, etc.)

Out-of-scope rows un-hedged. 'May not always' phrasings removed; each
adversary states unambiguously what veilor-os does NOT do.
2026-05-06 11:14:34 +01:00

12 KiB
Raw Blame History

Threat Model

Status: Final for v0.7 public launch. Honest scope.

veilor-os is a hardened daily-driver desktop. Not a paranoia OS, not an anonymity OS, not an isolation OS. This document exists so that security-conscious developers, journalists, and activists can decide whether the threat model fits their actual adversary before they trust the system.

If your adversary is on the "out of scope" list below, use a different tool. veilor-os will not save you, and we will not pretend otherwise.


In scope — what veilor-os defends against

Every row cites the file or setting that implements the mitigation, so the claim is auditable from a clean checkout.

Adversary / scenario veilor-os mitigation
Lost or stolen laptop, powered off LUKS2 aes-xts-plain64 + argon2id (mem=1 GiB, time=9) on root LV; swap is zram only — no persistent key material on disk. Defined in kickstart/veilor-os.ks part pv.veilor block.
Generic browser / email malware (drive-by RCE, malicious attachment) SELinux enforcing + targeted policy + custom veilor-systemd.te module (scripts/selinux/); sysctl knobs in /etc/sysctl.d/99-veilor-hardening.conf: kernel.kptr_restrict=2, kernel.yama.ptrace_scope=2, kernel.perf_event_paranoid=3, net.core.bpf_jit_harden=2, kernel.randomize_va_space=2, fs.suid_dumpable=0, dev.tty.ldisc_autoload=0. AppArmor profile skeletons in scripts/apparmor/ for Trivalent/Thorium/lm-studio (opt-in, complain mode, hardens to enforce per profile).
Console-side USB attack (BadUSB, rubber ducky, juice-jack) USBGuard daemon, ImplicitPolicyTarget=block, id-based rules in /etc/usbguard/rules.conf (vendor:product, not hash — survives dock replug). Empty allowlist on first boot; operator runs usbguard generate-policy after plugging trusted devices.
SSH brute-force / credential-stuffing /etc/ssh/sshd_config.d/10-veilor-hardening.conf: PasswordAuthentication no, PermitRootLogin no, AllowUsers admin, MaxAuthTries 3, X11Forwarding no, LogLevel VERBOSE. fail2ban sshd + pam-generic jails (journald backend) ban via firewalld rich-rule action.
Post-incident forensics ("what happened?") auditd rules in /etc/audit/rules.d/99-veilor-hardening.rules watch /etc/{passwd,shadow,group,sudoers,sudoers.d,ssh/sshd_config*,selinux,firewalld,cron.*,sysctl.*,systemd/system}, every privileged binary (sudo, su, passwd, mount, pkexec, …), init_module/finit_module/delete_module syscalls, and uid≥1000 perm/owner changes. Logs persist across reboot.
Supply-chain on the OS image itself Secure Boot enforced (Fedora signed shim → GRUB → kernel). v0.7 adds cosign-signed OCI image at ghcr.io/veilor/veilor-os:43, GPG-signed ISO + sha256 + .asc, plus our own MOK for out-of-tree module signing.
Unprivileged local user attempting LPE Root account locked (passwd -l root; passwd -S rootL); single admin user in wheel; pwquality.conf minlen=14, minclass=4, dictcheck on. Kernel lockdown=integrity, slab_nomerge, init_on_alloc=1, init_on_free=1, randomize_kstack_offset=on, vsyscall=none set in bootloader args. Module loading frozen 30 s after graphical boot via veilor-modules-lock.service.
Network-listening services as attack surface firewalld default zone = drop; only sshd answers. abrt*, cups, cups-browsed, geoclue, avahi-daemon, bluetooth, ModemManager, gssproxy, atd, pcscd.{socket,service} are masked; kdeconnectd and PackageKit are removed at the package level.
Time-based MITM (back-dated certs, replay) chrony with NTS authentication against time.cloudflare.com and nts.sth1/2.ntp.se (pool fallback only). systemd-resolved with DNS-over-TLS opportunistic, DNSSEC allow-downgrade, LLMNR off; resolvers Cloudflare 1.1.1.1 / 1.0.0.1, fallback Quad9 9.9.9.9 / 149.112.112.112.

Out of scope — what veilor-os does NOT defend against

These adversaries are unambiguously outside our scope. Pretending otherwise gets people hurt. If your adversary is on this list, pick a different tool.

Adversary / scenario Why veilor-os doesn't help Use instead
Firmware-level implant (UEFI, Intel ME, BMC, EC) veilor-os does not protect against firmware implants. Secure Boot validates the OS chain only; we do not flash, audit, or sign firmware below GRUB. Heads / coreboot on supported hardware.
Evil-maid attack on a running, unlocked system LUKS master keys live in RAM while the system is up. A physically present attacker can dump RAM (cold-boot, Thunderbolt DMA, debug header) and recover them. Power off when unattended. Disable Thunderbolt DMA in firmware. Qubes-in-a-Faraday-bag if you are that target.
Hardware keylogger / interposer between keyboard and machine veilor-os is software. Software cannot detect a passive hardware tap. Physical custody of the device. Tamper-evident seals.
Targeted RCE on the user session (browser 0-day, messenger exploit) KDE Plasma is not sandboxed. A logged-in compromise owns the user's data and tokens. SELinux confines daemons; it does not confine the desktop session. Qubes OS (per-app Xen VM isolation).
Side-channel attacks on AES (timing, cache, power, EM) veilor-os ships stock kernel crypto. We provide no constant-time or power-analysis guarantees beyond what the kernel and CPU deliver. Threat-specific HSM, air-gap.
Physical attack on a TPM2 chip (bus probe, glitch, decap) veilor-os does not bind keys to TPM2 in v0.7. Even when binding lands post-v1.0, TPM2 is not anti-tamper hardware. Off-device key custody (smartcard / YubiKey / OnlyKey).
Network-level traffic correlation / traffic analysis All packets leave the box on the local IP. veilor-os does not onion-route. Tails, Whonix, Tor.
Trust-on-first-use attacks (operator accepts a bad cert) veilor-os cannot override the operator's explicit decisions. Bad SSL or SSH host-key acceptance is out of scope. Enrolment policy, MDM, certificate pinning.
Adversary with sustained physical access and time Given unlimited physical time and tools, any laptop falls. Operational security, not OS choice.

Hardening tradeoffs (what you give up)

Hardening that breaks ordinary work gets called out, not hidden.

  • SELinux enforcing — some apps (proprietary, out-of-tree) ship without policy. Symptom: EACCES despite correct file perms. Workaround: write a local policy module; do not switch to permissive.
  • LUKS2 argon2id (mem=1 GB / time=9) — boot 530 s slower on older CPUs. The cost of a passphrase that survives a GPU attacker.
  • USBGuard default-block — every new device needs an explicit allow. First-boot: plug trusted devices in, run usbguard generate-policy. Forget this and your USB-C dock looks broken.
  • Module lockdown 30 s after graphical boot — out-of-tree drivers (NVIDIA proprietary, VirtualBox, out-of-tree wireguard) will fail. Load early via initramfs or use the in-tree alternative.
  • firewalld zone = drop — KDE Connect, mDNS printer discovery, SMB browsing don't work until explicitly opened. This is the point.
  • No PackageKit / no Flatpak by default — updates happen on your terms via dnf upgrade.

Where veilor-os IS like Tails / Whonix / Qubes

  • Threat model published. Transparency about scope is the price of being taken seriously.
  • Default-deny firewall (drop zone, ssh inbound only).
  • Encrypted at rest by default — LUKS2 + argon2id, no-disk-swap (zram).

Where veilor-os DIFFERS

  • Daily-driver target. Boot it once, install it, use it for years. Not a session-only / amnesia OS.
  • Single-VM / single-kernel. No per-app compartmentalisation. A browser RCE owns your session. (See "out of scope".)
  • Persistent identity by design. Your ~, your keys, your shell history persist. This is a feature for an operator, a misfeature for an activist evading correlation.

Comparison matrix

Scoring legend: shipped & on by default, ~ partial / opt-in, not provided, n/a not applicable to that distro's model. Project metrics are GitHub / Codeberg figures as of 2026-05.

Axis veilor-os Stock Fedora KDE Kicksecure Tails Qubes OS secureblue Athena OS
Encrypted at rest by default ✓ (LUKS2 argon2id, mem=1 GiB) ~ (optional in Anaconda) n/a (amnesic, session-only) ~ (optional)
MAC enforcing OOTB ✓ (SELinux + opt-in AppArmor) ✓ (SELinux) ✓ (AppArmor) ✓ (AppArmor) ✓ (per-VM) ✓ (SELinux) ✓ (AppArmor)
Default-deny firewall ✓ (firewalld zone=drop) ✓ (Tor-only)
USB default-block ✓ (USBGuard, id-rules) ✓ (sys-usb) ✓ (USBGuard)
Per-app isolation (VM/sandbox) ~ (AppArmor) ✓ (Xen VMs) ~ (Flatpak/bwrap)
Anonymity / Tor by default ~ (Whonix VMs)
Daily driver target (persistent) ✗ (amnesic) ✓ (heavy, hardware-partitioning)
Signed releases (cosign + GPG) ✓ (v0.7) ✓ (cosign on OCI) ~ (sha256 only)
Threat model published ✓ (this doc)
Hardware compatibility (laptops) ✓ (Fedora kernel) ~ ~ (live USB) ~ (Xen-pinned HCL) ✓ (Arch kernel)
Project size (contributors / stars, 2026-05) solo / pre-public n/a (Fedora-wide) small team / ~600 ~30 / ~3k large / ~5k ~30 / ~940, active monthly cadence ~8 / ~1.4k

Where veilor-os fits

Pick veilor-os if your job is to write code, edit docs, manage infrastructure, read mail, browse — and you want a desktop that won't quietly betray you to a generic adversary while you do it. You are the user, not the target of a state.

Pick Tails for amnesia and Tor by default. Qubes if you must assume any app could be compromised. Kicksecure for similar hardening on Debian. secureblue for a hardened atomic Fedora. Stock Fedora KDE if you just want Fedora with no opinions.


v0.7 public-launch checklist

These are the items that gate flipping the repo public and posting:

  • Threat model finalised and published (this document).
  • GPG-signed releases working (v0.4 dependency — ISO + sha256 + .asc).
  • Reproducible build verifiable from clean checkout (v0.4).
  • mkdocs-material (or Hugo) site live on veilor.org, generated from docs/. INSTALL, HARDENING, BUILD, ROADMAP, RELEASE, THREAT-MODEL, CONTRIBUTING all rendered.
  • Comparison + benchmark numbers published (cold boot, idle RAM, idle egress, suspend/resume) vs stock Fedora KDE.
  • Press kit page: wallpapers, logo SVG, screenshots, feature one-liner, signed quotes from early users.
  • "What veilor-os is not" preempt page — direct link from launch post. Answers "why not Qubes?", "why not Tails?", "why not just stock Fedora?" so the first hundred comments don't have to.
  • Comparison post drafted for r/linux, r/Fedora, HN. Same body, three formats. Lead with the threat model link, not the black wallpaper.
  • CHANGELOG.md tagged at v0.7.0 release commit; GitHub Release created with ISO + sha256 + .asc artefacts attached.
  • Repo flipped to public, veilor.org DNS pointed at the docs site, Mastodon / Matrix / SimpleX announcement queued.

Last reviewed: v0.7 draft. Update every minor release.