Threat model
What workstation-security defends against and what it does not, and why. Intended to give implementation engineers and security reviewers an honest picture in 15 minutes, so that expectations don't drift apart between "what we installed" and "what that actually solves".
Audience and operating assumptions
- Workstation, not a server. The assumption is a developer laptop or desktop with a single primary user who is largely root on their own machine. Server hardening (auditd baselines, SELinux mandatory policies, agent-based EDR) is out of scope.
- The user is technically competent. The user reads commit messages,
understands
sudo, knows what a GitHub PAT is. No childproof locks. - The workstation is connected to the internet and touches code. No
air-gapped enclave, no kiosk mode. It compiles, runs
npm install, usesgh. The threat model is built around that. - Compliance is a motivation, not an end goal. The controls exist because ISO 27001 / SOC 2 / NEN 7510 / BIO require them — not because they prevent the most likely attack. Important: a dev machine with ClamAV is not safer on the commodity-malware front (Linux malware is rare), but it is demonstrably in scope.
In scope — what we do defend
Commodity Linux malware
What: Classic viruses, trojans, ransomware payloads that land on a Linux dev machine via download or email attachment.
Defense:
- clamscan daily on /home (scan.sh via systemd timer).
- ClamAV daemon (clamd@scan or clamav-daemon) for realtime capabilities.
- wall notification on findings (visible only to logged-in sessions — see
gaps).
Honestly: Linux malware on a dev machine is low probability. The primary reason to run this is demonstrability for audit (A.8.7 / CC6.8 / NEN 7510 12.2 / BIO U.07.03), not "stopping Conficker".
Rootkits on the Linux host
What: Persistence tooling that hides beneath the OS (LD_PRELOAD hooks, kernel modules, modified system binaries).
Defense:
- rkhunter --check daily (rkhunter-check.sh via systemd timer).
- wall notification on warnings.
Honestly: rkhunter is signature-based and misses modern rootkits. For serious rootkit detection you need an EDR or YARA-based tooling. This is the minimum an auditor expects to see under "rootkit detection".
Not on WSL — there the false positives are so high that alarm fatigue
undermines the whole control (see README.md → WSL Support).
Supply-chain attacks via npm / pnpm / bun
What: An attacker publishes a malicious version of a legitimate package (event-stream, ua-parser-js, node-ipc patterns) or a typosquat. That version gets installed on a dev machine and runs postinstall scripts.
Defense:
- 7-day cooldown (install-pm-cooldown.sh) — refuses package versions younger
than N days. npm usually yanks malicious uploads within 24-48 hours; a 7-day
window catches them before they land in lockfiles.
- ~/.claude/CLAUDE.md rule: npm ci --ignore-scripts is the baseline,
postinstall enabled explicitly per package.
- Pre-commit gitleaks hook (via install-shell-tools.sh) — catches secrets
that would accidentally be committed into node_modules/ paths.
Honestly: a patient attacker can wait out the cooldown. It is defense in depth, not absolution. Against a targeted attack on a specific organization it barely helps.
Stolen GitHub PAT with dead-man's switch
What: An attacker compromises a gh-PAT and installs a service that
periodically polls api.github.com/user. When the user tries to revoke the
token (HTTP 40x), the service triggers rm -rf ~/ (CanisterSprawl-class
attack, carlini analysis 2026-05-12).
Defense:
- incident-token-revoke.sh — capture-first (sha256 + last4 for verify),
detect IOCs + heuristics, SIGKILL before systemctl stop (otherwise a
TERM trap catches the signal and still triggers rm -rf), evidence outside
$HOME (in /tmp/incident-<ts>/ so it survives the delete window), manual
revoke + verify.
- On WSL: scope warning at start that Windows-host persistence (Task Scheduler,
HKCU Run keys, startup folder) is outside this script.
Honestly: this is a specific attack class, not a general IR flow. Other token compromises (AWS IAM keys, Slack bot tokens) are not covered here — they need their own runbook.
Audit trail of what is configured on the system
What: An auditor asks "what runs on this workstation, when was it changed, and what does it do".
Defense:
- CHANGELOG.md with dated entries per change.
- check.sh as a read-only audit tool with a deterministic exit code.
- # role: marker on every script — grep -rn '^# role:' scripts/ gives the
complete process-boundaries map in a single scan.
- Logrotate on /var/log/clamav/ and /var/log/rkhunter.log (28 days
retained).
Out of scope — what we explicitly do NOT defend
Nation-state / APT actors
Kernel-level implants, custom in-memory droppers, zero-day exploits. Workstation-security is a baseline; against an actor with budget and patience no off-the-shelf solution works without EDR and proactive threat hunting. Acknowledge it in your risk register; workstation-security does not cover it.
Remote Access Trojans (RAT) after initial compromise
Once an attacker has bash on the machine (via phishing, browser exploit,
supply chain), they can either disable the defenses (root) or bypass them
(user-level persistence in ~/.local/bin that rkhunter misses). The IR script
catches one specific variant (gh-token-monitor); generic RAT detection is out
of scope.
Adversary-in-the-middle (AitM) on the network
A hostile Wi-Fi network, compromised proxy, or route injection. TLS
verification and VPN choice are separate controls that must live elsewhere
(/etc/ssh/ssh_config, browser TLS settings, organizational VPN policy).
Workstation-security does not interfere there.
Social engineering
Phishing, pretexting, vishing. Attacks on people. No script helps here — only training and policy.
Physical attacks
An attacker with physical access (stolen laptop, evil-maid attack, USB drop with malicious firmware). Disk encryption is the relevant control here (BitLocker/LUKS), but workstation-security does not install disk encryption — only checking for it is on the follow-up roadmap. For laptops in production: use LUKS or BitLocker, independent of this script.
Web browser attacks
A hostile website exploiting JS-engine bugs, or browser extensions that steal credentials. Here browser hardening (HSTS preload, extension policy via group policy or an MDM), uBlock Origin, and a good password manager are the relevant controls.
Server-side attacks
An attacker trying to SSH into this machine. SSH hardening (key-only auth, fail2ban, port changes) is a separate control. Workstation-security assumes the machine exposes no inbound services that are publicly reachable — a dev laptop, not a server.
Operating assumptions
The threat model depends on these assumptions; if one of them does not hold for your deployment, revisit which "out of scope" items actually remain out of scope.
| Assumption | What if it doesn't hold? |
|---|---|
| Single primary user with root | Multi-user dev-shared machine: rkhunter warnings can overwrite each other; reconsider permissions on /var/log/clamav/ |
| Internet connectivity available | Air-gapped: cooldown and signature updates stall; an offline update flow is required |
| The user installs no fresh packages within 7 days | Urgent CVE fix needed: per-project .npmrc with min-release-age=0, documented in CHANGELOG |
| systemd is the init (or WSL2 with opt-in) | OpenRC, init.d, runit: timers don't work; manual cron installation for scans needed |
/home is on a non-network filesystem |
NFS-mounted home: ClamAV scan can take hours; adjust scan.sh exclude patterns |
| The wall notification reaches the user | Headless / cloud-IDE environment: findings disappear unseen; add mail reporting (see incident-token-revoke.env.example for the pattern) |
Changes to this document
Update when: - A new script or installer is added → possibly expand "in scope" - An attack class that was previously out of scope comes into scope → document the reason + defense - An operating assumption changes → revise the out-of-scope section - A control is removed → explain why (moved to another tool, became redundant, etc.)