windows-wsl-security-verification — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited windows-wsl-security-verification (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Seed question: A dependency that ran as me may have been malicious — did anything take hold, is anything still resident, and what surface should I close while I'm looking?
Supply-chain compromise — a poisoned npm/PyPI release, a trojaned VS Code extension, a backdoored CI dependency — runs with your permissions the moment you install it. Its real prizes are credential theft and network exfiltration, not vandalizing your filesystem. This skill turns "am I compromised?" from an anxiety spiral into a finite procedure: a worst-first IOC sweep of both halves of a Windows + WSL2 box, a set of discriminators that keep ambiguous evidence from being misread in either direction, and a surface-reduction pass so the time spent looking also shrinks the next attack's room to move.
The discriminators are the value. Anyone can paste a checklist; what wrecks a triage is misreading the output — a content-grep "finding" your own research notes, a VirusTotal aggregate label screaming trojan at grayware, a web-filter popup read as an infection. Each step below carries the reading rule next to the check.
Windows host + WSL2, specifically. The checks are tool-concrete — Sysinternals Autoruns, Defender/third-party AV interplay, Task Scheduler, code --list-extensions, wsl.conf-era WSL2 — and tool-concrete is what makes them runnable rather than aspirational. macOS and bare-Linux boxes need sibling skills with their own tools (see Integration); this one does not pretend to cover them.
Verification, not hardening. This skill answers "did I get hit, and what can I close right now?" Hardening — sandbox distros, secrets isolation, egress control, container/microVM tiers — answers "make this box safer going forward": a different trigger, a different working mode (interactive, system-specific), a different job. This skill hands off to that track at the end; it does not bundle it.
The honest ceiling, stated up front: you cannot prove a machine clean — a good rootkit's job is to hide from exactly these checks. IOC triage is asymmetric: a hit is meaningful; a clean result raises confidence without being proof. Every verdict this skill produces says so.
TRIGGER (offer the triage — the user may not know to ask):
DO NOT TRIGGER / skip quietly:
Before any command, fix the mental model — wrong models misallocate the whole triage:
/mnt/c write access; (3) `\\wsl$` — Windows reading the Linux filesystem, secondary because it needs a Windows-side trigger.Run the checklist in reference/wsl-linux-ioc-checklist.md — known-bad package versions, rootkit preload, persistence vectors, planted SSH keys, shell-rc injection, executable .pth files, plus a secrets-exposure inventory. Each check there carries its command and what a hit means. Work through all of them even after an early "clean" — the vectors are independent; a clean ld.so.preload says nothing about cron.
For an IOC that is a named file, search with find -name (or hashes) — never content-grep. The moment you research an IOC, its name enters your shell history, session transcripts, and notes; grep -rl will then "find" it everywhere and the hits are your own research, not the artifact. A filename IOC exists as a file; test for the file. (Lived false alarm: four content-grep hits on a backdoor's .pth filename — all four were session transcripts discussing it; find -name came back empty.)
Run reference/windows-checklist.md: full AV scan, second-opinion on-demand scanner, Sysinternals Autoruns review (with its red/yellow/VT reading legend), code --list-extensions against verified-publisher namespaces, scheduled tasks. Two interplay rules from that pack worth knowing before you start:
Start-MpScan on top duplicates hours of I/O for no added coverage.Get-ScheduledTask; its Drivers tab is where BYOVD-class leftovers surface. One tool, several checklist lines.Most Windows steps are GUI- or host-side and can't be run from inside WSL — drive them as instructions to the user, and record their reported results in the output.
Every non-zero scan result goes through reference/interpreting-detections.md before it becomes a verdict. The two discriminators that pack carries:
PUA/PUP/Riskware with family: <the app itself>, and the "trojan" rows are generic ML/heuristic engines tripping on upx + persistence + detect-debug tags — the substance is "the app is junkware," not "a trojan is wearing its name." Those are different verdicts with different responses.Walk the Autoruns/extensions/tasks inventory once more with a different question: not "is this malicious?" but "do I actually use this?" Every autostart, service, and driver is attack surface + persistence real-estate + patch liability, whatever its intent. The pack's reduction list flags the special cases — BYOVD-class low-level drivers (hardware-monitor leftovers attackers bring in by name), remote-access tools, idle-compute rental agents, stale unquoted-path tasks. Uninstall/disable what isn't used; record what was removed and why.
BOX: <host / role>
THREAT CONTEXT: <what prompted this — package/CVE/detection/routine>
WSL-LINUX IOCs: <per-vector: HIT / clean / not-checked>
WINDOWS CHECKS: <AV / second-opinion / Autoruns / extensions / tasks: verdicts>
DETECTIONS READ: <each alert → malware / grayware / false-positive, with the named-family or process basis>
SURFACE REMOVED: <what was uninstalled or disabled, and why>
RESIDUAL GAPS: <what was not checked, plus the standing evasion ceiling>
VERDICT: CLEAN-SO-FAR (confidence raised, not proof) / COMPROMISED (→ contain: isolate, rotate credentials from a clean device, rebuild) / INCONCLUSIVE (name what would resolve it)
NEXT: <the hardening track, if wanted>Keep RESIDUAL GAPS and the verdict's parenthetical always — they are what keeps the output honest about the ceiling.
The grep false alarm. During a triage for a backdoored PyPI release, grep -rl on the dropper's filename returned four hits — heart-rate moment. All four were the session's own transcripts and notes, which contained the string because the IOC had just been researched. find -name across the filesystem: empty; the installed versions predated/postdated the bad releases. Verdict: clean on that vector. The lesson is Step 2 — a filename IOC is a file, so test for the file.
The 14/70 "trojan" that was grayware. Autoruns + VirusTotal flagged a torrent client at 14/70 with aggregate label "trojan.<appname>". Reading the engine rows: every named-family verdict said PUA/Riskware with the app itself as the family; the "trojan" rows were generic ML engines reacting to the packer and autostart behavior. Verdict: the real app, classified as junkware — uninstall because it's junk you don't use (Step 5), not because a trojan was found (Step 4). Same action, different verdict — and the difference matters for whether you must now rotate credentials.
The web-filter popup at 2am. An AV web-filter block fired while opening a new browser tab — no link clicked. Cause: the new-tab page's "top sites" tile re-requested a stored historical URL (favicon fetch), and the AV flagged that destination's reputation category. A page-load block of a remembered URL, originating from the browser, is not a malware finding; the box's verdict didn't change. Follow-up was privacy hygiene (remove the tile, clear the history entry), not incident response.
| Skill / component | Relationship |
|---|---|
| security-toolkit hooks (prompt-injection detection, dangerous-git blocking, PR-merge guard) | The prevention layer of the same plugin — they reduce the chance an agent-driven compromise happens. This skill is the detection/recovery layer for when prevention may have already failed. Same threat lens, different moment. |
| research-toolkit / iterative-verification | The evidence-honesty discipline this skill borrows: no confirmation = UNVERIFIED, not DISCONFIRMED. A vector you didn't check is "not-checked", never silently "clean". |
| macOS / bare-Linux verification siblings (not built yet) | The same "am I compromised?" trigger needs OS-specific tools elsewhere. Sibling skills, not a bloated cross-OS version of this one — they'll be built when those workflows are lived. |
| Hardening track (separate concern; skill-set to follow) | Where NEXT points: hardened sandbox distro (interop/automount off) → secrets out of the blast radius → default-deny egress → throwaway containers → gVisor → microVM, in reward-per-effort order. Kept out of this skill because its workflow is interactive, system-specific, and only a skill once it has been fully lived. |
Workflow position: fires on a compromise question or an unread detection → frame (Step 0) → sweep both sides (Steps 1, 3) with the discriminators (Steps 2, 4) → reduce surface (Step 5) → verdict with gaps stated → hand off to hardening if the user wants the forward-looking half.
A vasana is a pattern that persists across unrelated contexts. If during this task you notice such a pattern emerging, it may be worth capturing. This skill works best alongside the vasana skill and vasana hook from the Vasana System plugin.
Modify freely. Keep this section intact.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.