- ไคลเอนต์ HTTP axios ที่ใช้งานกันอย่างแพร่หลาย มีเวอร์ชันอันตราย 2 เวอร์ชันถูกเผยแพร่บน npm และเมื่อมีการติดตั้งจะปล่อย โทรจันสำหรับเข้าถึงเครื่องจากระยะไกล (RAT)
- ผู้โจมตีอัปโหลดแพ็กเกจอันตรายด้วยตนเองโดย ขโมยข้อมูลยืนยันตัวตนของบัญชีผู้ดูแลแพ็กเกจ เพื่อหลบเลี่ยง GitHub Actions
- เวอร์ชันอันตรายแทรก dependency ปลอม
plain-crypto-js@4.2.1 ซึ่งติดตั้ง RAT ผ่านสคริปต์ postinstall และลบร่องรอยออก
- RAT สามารถติดเครื่องได้ทั้ง macOS, Windows, Linux และสื่อสารกับเซิร์ฟเวอร์ C2 (
sfrclak.com:8000) เพื่อดาวน์โหลดเพย์โหลดเพิ่มเติม
- แม้ npm และ GitHub จะลบเวอร์ชันอันตรายออกอย่างรวดเร็ว แต่เหตุการณ์นี้ก็ย้ำให้เห็นอีกครั้งถึง ความสำคัญของการเสริมความปลอดภัยซัพพลายเชนและการปกป้องข้อมูลยืนยันตัวตน
ภาพรวมการโจมตีซัพพลายเชนของ axios บน npm
- เมื่อวันที่ 31 มีนาคม 2026 มีการเผยแพร่เวอร์ชันอันตราย 2 เวอร์ชันของ ไลบรารีไคลเอนต์ HTTP axios ที่ได้รับความนิยมสูงบน npm (
axios@1.14.1, axios@0.30.4)
- ผู้โจมตีขโมย ข้อมูลยืนยันตัวตน npm ของผู้ดูแลหลักของ axios เพื่อข้าม GitHub Actions CI/CD pipeline และเผยแพร่แพ็กเกจอันตรายด้วยตนเอง
- ทั้งสองเวอร์ชันได้แทรก dependency ปลอมชื่อ
plain-crypto-js@4.2.1 โดยแพ็กเกจนี้จะติดตั้ง โทรจันสำหรับเข้าถึงเครื่องจากระยะไกล (RAT) ผ่านสคริปต์ postinstall
- RAT มุ่งเป้าทั้ง macOS, Windows และ Linux และสื่อสารกับเซิร์ฟเวอร์ C2 (Command and Control) (
sfrclak.com:8000) เพื่อดึงเพย์โหลดระยะที่สองลงมา
- หลังติดตั้งแล้ว มัลแวร์จะลบโค้ดอันตรายและร่องรอย พร้อมแทนที่ด้วย
package.json ที่ดูสะอาด เพื่อ หลบเลี่ยงการตรวจจับทางนิติวิทยาศาสตร์ดิจิทัล
ไทม์ไลน์การโจมตี
- 30 มีนาคม 05:57 UTC: เผยแพร่
plain-crypto-js@4.2.0 (เวอร์ชันปกติ)
- 30 มีนาคม 23:59 UTC: เผยแพร่
plain-crypto-js@4.2.1 (เวอร์ชันอันตราย) พร้อมเพิ่ม hook postinstall
- 31 มีนาคม 00:21 UTC: เผยแพร่
axios@1.14.1 พร้อมแทรก dependency อันตราย
- 31 มีนาคม 01:00 UTC: เผยแพร่
axios@0.30.4 พร้อมแทรก dependency อันตรายเดียวกัน
- 31 มีนาคม 03:15 UTC: npm ลบสองเวอร์ชันอันตรายออก
- 31 มีนาคม 04:26 UTC: npm แทนที่
plain-crypto-js ด้วย security holder stub (0.0.1-security.0)
ภาพรวมของ axios
- axios คือ ไคลเอนต์ HTTP ที่ถูกใช้งานแพร่หลายที่สุดตัวหนึ่งใน ecosystem ของ JavaScript ใช้ได้ทั้งกับ Node.js และเบราว์เซอร์
- มียอดดาวน์โหลดต่อสัปดาห์มากกว่า 300 ล้านครั้ง ดังนั้นแม้จะมีการปล่อยเวอร์ชันอันตรายเพียงครั้งเดียวก็อาจ สร้างความเสียหายเป็นวงกว้าง
- นักพัฒนาทั่วไปยากจะสังเกตได้ว่ามีการติดตั้งโค้ดอันตรายระหว่าง
npm install
ขั้นตอนการโจมตี
-
ระยะที่ 1 — ยึดบัญชีผู้ดูแลแพ็กเกจ
- ผู้โจมตียึด บัญชี npm
jasonsaayman และเปลี่ยนอีเมลเป็น ifstap@proton.me
- จากนั้นเผยแพร่บิลด์อันตรายไปยัง ทั้ง release branch สาย 1.x และ 0.x
- รีลีสปกติจะเผยแพร่ผ่าน OIDC Trusted Publisher ของ GitHub Actions แต่
axios@1.14.1 ถูกเผยแพร่แบบ manual จึงไม่มี gitHead และไม่มีลายเซ็น OIDC
- คาดว่าผู้โจมตีใช้ npm access token ที่มีอายุยาว
-
ระยะที่ 2 — ปล่อย dependency อันตรายล่วงหน้า
plain-crypto-js@4.2.1 ถูกเผยแพร่จากบัญชี nrwise@proton.me
- แพ็กเกจนี้ ปลอมตัวเป็น
crypto-js โดยใช้คำอธิบายและ URL repository เดียวกัน
- มี hook
"postinstall": "node setup.js" เพื่อให้รันอัตโนมัติระหว่างติดตั้ง
- หลังการโจมตี มีการแทนที่
package.md เป็น package.json เพื่อ เตรียมลบหลักฐาน
-
ระยะที่ 3 — แทรก dependency ลงใน axios
- เพิ่ม
plain-crypto-js@^4.2.1 เป็น runtime dependency
- แต่ในโค้ดไม่มีการ import เลยแม้แต่ครั้งเดียว → เป็น phantom dependency
- เมื่อรัน
npm install จะถูกติดตั้งอัตโนมัติและเรียกสคริปต์ postinstall
การวิเคราะห์ RAT dropper (setup.js)
-
เทคนิคการทำ obfuscation
- เก็บสตริงแบบเข้ารหัสไว้ในอาร์เรย์
stq[] และถอดรหัสด้วย _trans_1 (XOR) กับ _trans_2 (Base64+ย้อนลำดับ)
- URL ของ C2 คือ
http://sfrclak.com:8000/6202033
- สตริงที่ถอดรหัสแล้วมีทั้งตัวระบุระบบปฏิบัติการ (
win32, darwin), พาธไฟล์ และคำสั่งเชลล์
-
เพย์โหลดตามแพลตฟอร์ม
-
macOS
- เขียน AppleScript ลงใน
/tmp แล้วรันผ่าน osascript
- ดึงไบนารี RAT จาก C2 มาเก็บและรันที่
/Library/Caches/com.apple.act.mond
- ชื่อไฟล์ถูก ปลอมให้ดูเหมือน Apple system daemon
-
Windows
- ค้นหาเส้นทาง PowerShell แล้วคัดลอกไปที่
%PROGRAMDATA%\\wt.exe
- ใช้ VBScript ดาวน์โหลดและรัน PowerShell RAT จาก C2
- ไฟล์ชั่วคราว (
.vbs, .ps1) จะถูกลบหลังรัน
-
Linux
- ใช้
curl ดาวน์โหลด /tmp/ld.py แล้วรันด้วย nohup python3
- ไฟล์
/tmp/ld.py จะยังคงอยู่
- ทั้งสามแพลตฟอร์มใช้ POST body ไปยัง
packages.npm.org/product0~2 เพื่อ ปลอมตัวให้ดูเหมือนทราฟฟิก npm ปกติ
-
การลบตัวเองและการซ่อนร่องรอย
- ลบ
setup.js และ package.json
- แทนที่
package.md กลับเป็น package.json เพื่อ ปลอมเป็นแพ็กเกจปกติ
- หลังจากนั้นจะตรวจพบได้ยากผ่าน
npm audit หรือการตรวจสอบด้วยมือ
- อย่างไรก็ตาม การมีอยู่ของ
node_modules/plain-crypto-js/ เองก็ถือเป็นหลักฐานการติดเชื้อ
การยืนยันการทำงานผ่าน StepSecurity Harden-Runner
- Harden-Runner บันทึก เหตุการณ์เครือข่าย โปรเซส และไฟล์แบบเรียลไทม์ บน GitHub Actions
- เมื่อติดตั้ง
axios@1.14.1 พบการเชื่อมต่อ C2 สองครั้ง (curl, nohup)
- การเชื่อมต่อครั้งแรกเกิดขึ้น 2 วินาทีหลังเริ่ม
npm install
- ครั้งที่สองเกิดขึ้นหลังจาก 36 วินาที และยังทำงานต่อเป็นโปรเซสเบื้องหลัง
- จากการวิเคราะห์ process tree พบว่าโปรเซส
nohup กลายเป็น orphan process ใต้ PID 1(init) และยังคงทำงานต่อ
- ในบันทึกเหตุการณ์ไฟล์พบว่า
package.json ถูกเขียนทับสองครั้ง
- ครั้งแรก: เขียนเวอร์ชันอันตรายระหว่างติดตั้ง
- ครั้งที่สอง: หลัง 36 วินาที ถูกแทนที่ด้วย stub ที่สะอาด
ตัวบ่งชี้การบุกรุก (IOC)
-
แพ็กเกจ npm อันตราย
- axios@1.14.1 · shasum: 2553649f232204966871cea80a5d0d6adc700ca
- axios@0.30.4 · shasum: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
- plain-crypto-js@4.2.1 · shasum: 07d889e2dadce6f3910dcbc253317d28ca61c766
-
เครือข่าย
-
พาธไฟล์
- macOS:
/Library/Caches/com.apple.act.mond
- Windows:
%PROGRAMDATA%\\wt.exe
- Linux:
/tmp/ld.py
-
บัญชีผู้โจมตี
jasonsaayman (ผู้ดูแลที่ถูกยึดบัญชี)
nrwise (บัญชีที่ผู้โจมตีสร้าง)
-
เวอร์ชันปลอดภัย
ขั้นตอนการตรวจสอบผลกระทบและการตอบสนอง
- ตรวจสอบ 1.14.1 / 0.30.4 ด้วย
npm list axios หรือใน package-lock.json
- ตรวจสอบว่ามี
node_modules/plain-crypto-js อยู่หรือไม่
- หากพบไฟล์ RAT ตามแต่ละระบบปฏิบัติการ ให้ถือว่า ระบบถูกยึดเต็มรูปแบบ
- ตรวจสอบบันทึก CI/CD ว่าเคยติดตั้งเวอร์ชันดังกล่าวหรือไม่ และ ต้องเปลี่ยนความลับและโทเคนทั้งหมด
ขั้นตอนการกู้คืน
- ล็อก axios ไว้ที่ เวอร์ชันปลอดภัย (1.14.0 หรือ 0.30.3)
- ลบโฟลเดอร์
plain-crypto-js แล้วติดตั้งใหม่ด้วย npm install --ignore-scripts
- หากพบร่องรอย RAT ให้สร้างระบบใหม่
- หมุนเวียนข้อมูลยืนยันตัวตนทั้งหมด (AWS, SSH, CI/CD ฯลฯ)
- ตรวจสอบ CI/CD pipeline และเปลี่ยน secret ทั้งหมด
- ใช้ตัวเลือก
--ignore-scripts สำหรับงาน build อัตโนมัติ
- บล็อกโดเมน/IP ของ C2 ด้วยไฟร์วอลล์หรือ
/etc/hosts
ความสามารถของ StepSecurity Enterprise
-
Harden-Runner
- ใช้ allowlist การเชื่อมต่อเครือข่ายขาออก บน GitHub Actions
- บล็อกและบันทึกทราฟฟิกที่ผิดปกติ
- สามารถ บล็อกการเชื่อมต่อ
sfrclak.com:8000 ได้ล่วงหน้า
-
Dev Machine Guard
- เฝ้าติดตามแพ็กเกจ npm ที่ติดตั้งบนเครื่องนักพัฒนาแบบเรียลไทม์
- ตรวจจับเครื่องที่ติดตั้ง
axios@1.14.1, 0.30.4 ได้ทันที
-
npm Package Cooldown Check
- กำหนด ช่วงเวลาหน่วงก่อนอนุญาตให้ติดตั้ง สำหรับแพ็กเกจที่เพิ่งเผยแพร่
- ช่วยตรวจจับการปล่อยแพ็กเกจอันตรายอย่างรวดเร็ว เช่น
plain-crypto-js@4.2.1
-
Compromised Updates Check
- บล็อกการ merge PR โดยอิงฐานข้อมูลแพ็กเกจอันตรายแบบเรียลไทม์
- ลงทะเบียน
axios@1.14.1, plain-crypto-js@4.2.1 ได้ทันที
-
Package Search
- ค้นหาตำแหน่งที่มีการนำแพ็กเกจเฉพาะเข้าใช้ใน PR และ repository ทั่วทั้งองค์กร
- ระบุขอบเขตผลกระทบ (repository, team, PR) ได้ทันที
-
AI Package Analyst
- เฝ้าระวัง npm registry แบบเรียลไทม์และใช้ การตรวจจับมัลแวร์ตามพฤติกรรม
- ตรวจพบทั้งสองเวอร์ชันอันตรายภายในไม่กี่นาทีหลังเผยแพร่
-
Threat Center Alert
- ให้ การแจ้งเตือนข่าวกรองภัยคุกคาม ที่มีทั้งสรุปการโจมตี IOC และขั้นตอนตอบสนอง
- เชื่อมต่อกับ SIEM เพื่อให้มองเห็นสถานะได้แบบเรียลไทม์
คำขอบคุณ
- ผู้ดูแล axios และชุมชนตอบสนองอย่างรวดเร็วผ่าน GitHub issue #10604
- GitHub ระงับบัญชีที่ถูกยึด ขณะที่ npm ลบเวอร์ชันอันตรายและใช้ security holder
- ความร่วมมือระหว่างผู้ดูแล GitHub และ npm ช่วยลดความเสียหายต่อผู้พัฒนาทั่วโลก
2 ความคิดเห็น
ไม่เคยคิดเลยว่าแพ็กเกจระดับนี้จะโดนเจาะได้ แต่ axios นี่เกินคาดจริง ๆ
ความคิดเห็นจาก Hacker News
ตอนนี้ npm, bun, pnpm และ uv ต่างก็รองรับ การกำหนดช่วงเวลาขั้นต่ำก่อนปล่อยแพ็กเกจ แล้ว
ฉันเพิ่ม
ignore-scripts=trueไว้ใน~/.npmrcซึ่งแค่ตั้งค่านี้ก็ช่วยบรรเทาช่องโหว่ได้แล้วbun และ pnpm จะไม่รัน lifecycle scripts โดยค่าเริ่มต้น
ตัวอย่างการตั้งค่าของแต่ละ package manager มีดังนี้:
exclude-newer = "7 days"min-release-age=7minimum-release-age=10080minimumReleaseAge = 604800ที่น่าสนใจคือแต่ละตัวใช้ หน่วยเวลาไม่เหมือนกัน
ถ้าใช้ LLM agent การตั้งค่านี้อาจทำให้เกิดความล้มเหลวได้ จึงควรเพิ่มคำแนะนำที่เกี่ยวข้องไว้ใน
AGENTS.mdหรือCLAUDE.mdtimeoutMinutesแทนtimeoutmin-release-age=7 # daysอาจไม่ถูกนำไปใช้จริงnpmMinimalAgeGate: "3d"ใน~/.yarnrc.ymlได้หลายคนช็อกกับข่าวที่ Axios ถูกโจมตีแบบ supply chain attack
ในตัว Axios เองไม่มีโค้ดอันตราย แต่มีการฉีด dependency ปลอมชื่อ
plain-crypto-js@4.2.1เข้ามาเพื่อรัน postinstall script ที่ติดตั้ง RAT (remote access trojan)ถือเป็นข่าวดีสำหรับผู้ใช้ที่ต้องอนุมัติ postinstall script เองแบบ pnpm หรือ bun
มีคนอ้างว่า package manager คือ การทดลองที่ล้มเหลว
มี C library คุณภาพสูงหลายตัวที่มาในรูปไฟล์
.cเดียวแบบ SQLite และแนวทางแบบนี้ช่วยหลีกเลี่ยงปัญหา transitive dependency ได้พื้นที่โจมตีส่วนใหญ่มาจาก dependency ทางอ้อมเหล่านี้
แม้แต่ OpenSSL ก็ยังอยู่ระหว่าง การเขียนใหม่ เพราะปัญหาคุณภาพโค้ด และฝั่ง JS ก็ขยาย standard library ได้ยากจนเกิด polyfill กระจัดกระจาย จำนวนมาก
จึงมีข้อเสนอให้คลังอย่าง npm ยกระดับมาตรฐานคุณภาพ และอนุญาตให้เฉพาะผู้ดูแลที่รับผิดชอบเท่านั้นเผยแพร่แพ็กเกจ
มีมุกว่าตนเริ่มต้นวันด้วยคำทักทายเชิงประชดว่า “วันนี้ npm package ตัวไหนโดนเจาะอีกล่ะ?”
สำหรับผู้ใช้ Linux มีคำแนะนำให้ใช้ bwrap เพื่อ sandbox build logic ทั้งหมดของ npm, pip, cargo, gradle ฯลฯ
bwrap ให้สภาพแวดล้อมแยกเหมือน Docker แต่ไม่ต้องมี image และ Flatpak ก็ใช้เทคโนโลยีเดียวกัน
เวลาปล่อยขึ้นเซิร์ฟเวอร์ สิ่งสำคัญคือ container hardening และการปฏิบัติกับ CI/CD ว่าเป็นพื้นที่ที่ไม่น่าเชื่อถือ
ตอนรัน AI ก็ควรใช้ sandbox แบบเดียวกันด้วย
requireโค้ดภายในก็อาจถูกรันได้แล้วเมื่อเห็นปัญหา dependency ซ้ำ ๆ หลายคนจึง กังวลว่า ecosystem ของ Rust จะเจอแบบเดียวกันสักวันไหม
แม้การทำ standard library ให้ใหญ่ขึ้นจะไม่ง่าย แต่ก็จำเป็นต้องมี ระบบรับประกันคุณภาพแพ็กเกจที่เชื่อถือได้
หลายคนบอกว่า AI ทำให้ภาระงานเพิ่มแบบนี้พอเป็นไปได้ และจริง ๆ แล้วน่าจะทำแบบนี้มาตั้งนานแล้ว
หลักปฏิบัติสำคัญ เพื่อลดความเสี่ยงจาก NPM supply chain attack
--frozen-lockfileก็ป้องกันได้มากพอแล้วเมื่อมีคนถามว่า “ถ้าอยากเลี่ยงการโจมตีแบบนี้ให้หมดจริง ๆ ต้องทำยังไง?”
ก็มีความเห็นว่าอยาก ย้ายไปใช้ Qubes OS เพื่อแยก password manager กับสภาพแวดล้อม build ออกจากกันโดยสมบูรณ์
พวกเขาเปรียบเทียบว่านี่เหมือน อุปกรณ์ป้องกันส่วนบุคคล (PPE) ในห้องแล็บเคมี คือสภาพแวดล้อมพัฒนาก็ควรมีการแยกและการป้องกันเช่นกัน
pip เองก็เริ่มบล็อกการติดตั้งนอก virtualenv แล้ว และหวังว่าในอนาคต package manager จะมี ตัวเลือกปฏิเสธการรันนอก sandbox
ตอนนี้ pnpm และ bun จะ เพิกเฉยต่อ postinstall script โดยค่าเริ่มต้น แล้ว แต่ npm ยังรันอยู่
ควรตั้งค่า
ignore-scripts=trueใน~/.npmrcnpm ยังมียอดดาวน์โหลด 80 ล้านครั้งต่อสัปดาห์
มีการคาดเดาว่าการรั่วไหลของ credential ในเหตุการณ์นี้น่าจะ สืบเนื่องมาจากเหตุการณ์ LiteLLM ก่อนหน้า
หลายคนรู้สึกไม่สบายใจกับการใช้ Python หรือ Node.js แต่ก็เห็นว่านี่เป็น ปัญหาทั่วไป