Skip to content

v0.1.9 — LustLess (hardening: local tamper, fail-open DNS, poisoned queues)

Choose a tag to compare

@HenryGetz HenryGetz released this 14 Oct 14:55
· 9 commits to main since this release

Linux accountability client (Covenant Eyes-compatible, clean-room reimplementation).

Install

curl -fsSL https://github.com/HenryGetz/LustLess/releases/latest/download/install.sh | sudo bash

Detects your distro, downloads the matching package, installs it with the
native tool, starts the agent — and the sign-in window opens. Log in there.
Other ways:

Distro File Command
Debian / Ubuntu / Zorin / Mint lustless_0.1.9_amd64.deb sudo apt install ./lustless_0.1.9_amd64.deb
Fedora lustless-0.1.9-1.x86_64.rpm sudo dnf install ./lustless-0.1.9-1.x86_64.rpm
Bazzite / immutable Fedora lustless-0.1.9-1.x86_64.rpm sudo rpm-ostree install ./lustless-0.1.9-1.x86_64.rpm && reboot
Arch / EndeavourOS / SteamOS lustless-0.1.9-1-x86_64.pkg.tar.zst sudo pacman -U ./lustless-0.1.9-1-x86_64.pkg.tar.zst
Alpine lustless-0.1.9-r0.apk sudo apk add --allow-untrusted ./lustless-0.1.9-r0.apk

Uninstall: sudo apt purge lustless (or the dnf/rpm-ostree/pacman/apk
equivalent) — restores the DNS, browser-policy and polkit state exactly as
found.

What's new — hardening

Two focused reviews (local attack surface; error paths) were run against the
shipped code and everything they found is fixed here. In an accountability
client the person at the keyboard is the adversary, so the tamper findings are
as important as crashes.

Local tamper, previously possible for any unprivileged user:

  • Dashboard tokens were validated and then discarded, so any local user could
    fetch a token over the 0666 IPC socket and drive the signed-in session: sign
    it out, set the weakest filter level, or allow-list *. Mutations now require
    the token to own the session.
  • 0x4c USER_LOGOUT had no ownership check — any uid could force a sign-out
    (and with fail_closed_when_signed_out = false, stop the filter).
  • 0x61/0x43/0x4d/0x54/0x67 leaked the signed-in username, filter
    state and outbox path to any uid, minted a dashboard token for them, and let
    them trigger diagnostics, outbox flushes and a feed fetch.
  • The break-glass audit line now carries the promised
    org.lustless.break-glass uid=… reason=… tag; denials are distinguishable.
  • The agent's session-token file no longer falls back to world-writable /tmp
    (symlink capture) and refuses a symlinked directory.

Fail-open and queue defects:

  • Filtering could silently be off while the daemon looked healthy: a DNS
    forwarder that failed to build or bind only logged. It is now marked Outage
    and reported, dns.listen/ports are validated at startup, and an unparsable
    config refuses to start instead of quietly using defaults.
  • Block pages never loaded: the synthesized CNAME was owned by the block
    host instead of the queried name, so a stub resolver returned NODATA. Now
    RFC 1034-shaped.
  • A fail-closed classifier exit counted as clean (it prints bye and
    returns 1), bypassing the crash budget, metric and escalation and respawning
    every 5 s forever with screen accountability off.
  • Rejected (4xx) batches poisoned the upload queue forever (drop_invalid
    matched only locally-invalid rows, so nothing was deleted and the batch was
    re-claimed oldest-first). Deterministic rejections now delete exactly the
    claimed rows.
  • A second daemon could run, sharing the outbox/spool/crash ledger and
    reporting a false crash: lustlessd now holds an exclusive flock.
  • Spool orphans are swept by the daemon (previously only at classifier
    startup), shutdown aborts overrunning tasks, and the staged update payload is
    removed after install.

Workspace suite: 313 passed, 0 failed. Everything from 0.1.8 (crash
pipeline), 0.1.7 (parity audit, real-model proof), 0.1.6 (Zorin Lite branding),
0.1.5 (DNS that stays alive) and 0.1.4 (agent main loop) is unchanged.