บริบท
เมื่อไม่นานมานี้ ระบบตรวจสอบความปลอดภัย MistEye ได้รับข้อมูลเกี่ยวกับการปรากฏตัวของเวอร์ชันผิดปกติในแพ็กเกจ npm หลายตัวภายใต้กลุ่ม Red Hat Cloud Services ครั้งนี้เกี่ยวข้องกับแพ็กเกจ npm 32 ตัวและเวอร์ชัน 96 เวอร์ชัน จากกลุ่มนี้ เราเลือกตัวอย่างท้องถิ่น 3 ตัวเพื่อวิเคราะห์แบบออฟไลน์อย่างละเอียด: ตัวอย่างเหล่านี้ไม่ใช่แพ็กเกจที่เลียนแบบชื่อหรือ typosquatting แต่เป็นเวอร์ชันที่แท้จริงภายใต้ scope @redhat-cloud-services; จากโค้ดต้นฉบับของตัวอย่างสามารถยืนยันได้ว่า tarball ของมันมีการฝัง loader ที่ถูกเข้ารหัสหลายชั้นซึ่งจะถูกกระตุ้นอัตโนมัติในขั้นตอนการติดตั้ง
หลังจากกู้คืนอย่างสมบูรณ์แล้ว สามารถยืนยันได้ว่าโหลดหลักของตัวอย่างทั้ง 3 ตัวมีความสามารถในการอ่านหน่วยความจำของ GitHub Actions Runner, การรวบรวมข้อมูลรับรองจากหลายคลาวด์และท้องถิ่น, การส่งข้อมูลผ่าน GitHub API และ dead-drop, การแทรกซึมใน GitHub workflow, การแพร่กระจายตัวเองผ่าน npm, การคงอยู่ถาวรผ่าน Claude Code / VS Code / systemd / LaunchAgent, การต่อต้าน Harden-Runner / StepSecurity, และการตรวจจับ EDR / ผลิตภัณฑ์ด้านความปลอดภัย จากขอบเขตของความสามารถ ผู้ที่อาจได้รับผลกระทบรวมถึงเครื่องของนักพัฒนา, CI/CD Runner, คอนเทนเนอร์การสร้าง, รีพอสิทอรี GitHub, GitHub Actions workflow, เส้นทางการเผยแพร่ npm และข้อมูลรับรองของสภาพแวดล้อมคลาวด์; ขอบเขตผลกระทบจริงจำเป็นต้องยืนยันเพิ่มเติมโดยใช้บันทึกการติดตั้ง, การตรวจสอบรีพอสิทอรี และข้อมูลการวัดจากระบบ
จากโครงสร้างโค้ด เส้นทางการแพร่กระจาย และการรวมกันของความสามารถ โปรแกรมโทรจันนี้จัดอยู่ในประเภทที่แปรเปลี่ยนมาจาก Shai-Hulud
MistEye ตอบกลับ
MistEye เป็นระบบข้อมูลภัยคุกคามและระบบติดตามความปลอดภัยแบบไดนามิกสำหรับ Web3 ที่ SlowMist พัฒนาขึ้นเอง โดยรวมความสามารถในการติดตามความปลอดภัยและการรวบรวมข้อมูลภัยคุกคาม เพื่อให้ผู้ใช้ได้รับการแจ้งเตือนความเสี่ยงแบบเรียลไทม์และการปกป้องสินทรัพย์
หลังจากจับกุมเหตุการณ์การปลอมแปลงซัพพลายเชนของแพ็กเกจ npm ของ Red Hat Cloud Services และตัวอย่างที่เป็นอันตรายที่เกี่ยวข้อง ระบบ MistEye ได้กระตุ้นการแจ้งเตือนระดับสูง และทำการวิเคราะห์ระบบเกี่ยวกับโครงสร้างที่ถูกเข้ารหัส กระบวนการถอดรหัสโหลด ความสามารถในการกู้คืน และ IOC
(https://enterprise.misteye.io/threat-intelligence/SM-2026-378450)
ภาพรวมของโซ่การโจมตี
ส่วนการวิเคราะห์ทางเทคนิคของบทความนี้อิงจากการวิเคราะห์แบบออฟไลน์และแบบคงที่เท่านั้น โดยทำการแกะแพ็ก ถอดรหัส และยืนยันการถอดรหัสความสับสนของตัวอย่าง npm tgz 3 ตัว
ตัวอย่างที่ได้รับการตรวจสอบในครั้งนี้มีดังนี้:
@redhat-cloud-services/frontend-components-config
เวอร์ชัน: 6.11.3
tgz SHA-256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060
@redhat-cloud-services/types
เวอร์ชัน: 3.6.1
tgz SHA-256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558
@redhat-cloud-services/rule-components
เวอร์ชัน: 4.7.2
tgz SHA-256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f
จุดเข้าสู่การโจมตีของตัวอย่างทั้งสามนั้นเหมือนกันทั้งหมด: ในไฟล์ package.json มี scripts.preinstall = "node index.js" ทั้งหมด ซึ่งหมายความว่า เมื่อโฮสต์ของนักพัฒนาหรือสภาพแวดล้อม CI/CD ติดตั้งเวอร์ชันเหล่านี้ ไฟล์ index.js ที่รูทจะถูกดำเนินการอัตโนมัติในขั้นตอนการติดตั้ง โดยไม่จำเป็นต้องมีการนำเข้าหรือเรียกใช้โค้ดธุรกิจอย่างชัดเจนจากผู้ใช้
ตัวอย่างสามตัวมีรหัสความเสี่ยงหลักเดียวกัน แต่มีพารามิเตอร์ห่อภายนอกต่างกัน กล่าวคือ ตัวอย่างทั้งสามใช้ค่าการเลื่อน ROT/Caesar และคีย์/IV/แท็ก AES-GCM ที่แตกต่างกัน ซึ่งทำให้คุณลักษณะคงที่ที่อิงจาก hash ของห่อภายนอก คีย์คงที่ หรือค่าการเลื่อนคงที่ยากต่อการนำกลับมาใช้ใหม่ข้ามตัวอย่าง อย่างไรก็ตาม ตัวนำร่องสภาพแวดล้อมการรัน Bun และ hash ของรหัสความเสี่ยงหลักหลังถอดรหัสเหมือนกันทั้งหมด: หนึ่งคือโมดูลช่วยเริ่มต้นสำหรับเตรียมสภาพแวดล้อมการรัน Bun อีกอันคือรหัสความเสี่ยงหลักที่มีฟังก์ชันอันตรายจริง บทความนี้เรียกทั้งสองส่วนว่า "ตัวนำร่องสภาพแวดล้อมการรัน Bun (ชื่อตัวแปรในโค้ด _b)" และ "รหัสความเสี่ยงหลัก (ชื่อตัวแปรในโค้ด _p)"
สายการโจมตีที่กู้คืนได้คือ:

Technical Analysis
1. ช่องทางเข้า: การโจมตีด้วยการแย่งชิงสคริปต์ของ npm lifecycle
ตัวอย่างทั้งสามถูกกระตุ้นผ่านฮุกชีวิต cycle preinstall ใน package.json:
"scripts": {
"preinstall": "node index.js"
}
preinstall จะถูกดำเนินการอัตโนมัติในขั้นตอนการติดตั้งของ npm สำหรับคอมโพเนนต์เว็บฟรอนต์ทั่วไป คำจำกัดความประเภท หรือแพ็กเกจส่วนประกอบกฎ ไม่จำเป็นต้องรันไฟล์ JavaScript ขนาดใหญ่ที่รูทในขั้นตอนการติดตั้ง นี่คือสัญญาณผิดปกติที่ชัดเจนที่สุด
หลักฐานระดับตัวอย่างมีดังนี้:
@redhat-cloud-services/frontend-components-config@6.11.3
- main: lib/index.js
- ฟิลด์ files: ["/lib", "/bin"]
- รูทไดเรกทอรี index.js SHA-256: 545a1838c66e1771f58d84a17b3e1841e5eeab91a73f4ccc59c9492450a6d9c0
@redhat-cloud-services/types@3.6.1
- main: index.d.ts
- ฟิลด์ files: ยังไม่ได้ตั้งค่า
- รูทไดเรกทอรี index.js SHA-256: b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966
@redhat-cloud-services/rule-components@4.7.2
- main: index.js
- ฟิลด์ files: ยังไม่ได้ตั้งค่า
- รูทไดเรกทอรี index.js SHA-256: 1a30a9abe20bab121aaa75ed040565af14e6cdfb745609ee0e7b94a2d814fb9c
ในกรณีนี้ ฟิลด์ files ของ frontend-components-config@6.11.3 ประกาศเฉพาะ "/lib" และ "/bin" แต่ในรูทของ tarball มีไฟล์ index.js เพิ่มเติมที่ถูกเรียกใช้โดย preinstall ข้อผิดพลาดนี้ใช้ได้เฉพาะกับตัวอย่างนี้เท่านั้น; types@3.6.1 และ rule-components@4.7.2 ไม่ได้ตั้งค่าฟิลด์ files จึงไม่ควรสรุปข้อผิดพลาดนี้ให้ครอบคลุมตัวอย่างทั้งหมด
2. ชั้นที่หนึ่ง: อาเรย์ตัวเลข + การแทนที่ตัวอักษร ROT/Caesar
ไฟล์ index.js ที่รูทของตัวอย่างทั้งสามเป็นไฟล์ JavaScript บรรทัดเดียวขนาดใหญ่มาก มีโครงสร้างเหมือนกัน โดยมีตัวกรอบหลักเป็น try { eval(...) } catch (...)
ตัวแพ็กเกจแรกจะแปลงอาร์เรย์ตัวเลขขนาดใหญ่กลับเป็นสตริงผ่าน String.fromCharCode แล้วจึงเลื่อนตัวอักษรภาษาอังกฤษในสตริงด้วยการเลื่อน ROT/Caesar สุดท้ายจะส่งผลลัพธ์ที่ถอดรหัสให้ eval ดำเนินการ การจัดการข้อผิดพลาดจะแสดงเฉพาะคำว่า wrapper: เท่านั้น เพื่อลดการเปิดเผยข้อผิดพลาดที่ชัดเจนเมื่อการติดตั้งล้มเหลว
ค่าการเลื่อนชั้นนอกและ Stage 2 hash ของตัวอย่างสามตัวคือ:
frontend-components-config@6.11.3
ขนาดของ index.js: 4,294,798 ไบต์
ROT/Caesar shift: 10
ขั้นตอนที่ 2 SHA-256: b19c2fd48535c8c40aeb3e627ce92775f33ef9292611767bb1236c238e6f90cc
types@3.6.1
ขนาดของ index.js: 4,135,588 ไบต์
ROT/Caesar shift: 4
ขั้นตอนที่ 2 SHA-256: 9c0425aa6e6d7792ac38d24f3e7245f42fcaa553ddfeb6bd97677017f10c3b75
rule-components@4.7.2
ขนาดของ index.js: 4,294,336 ไบต์
ROT/Caesar shift: 11
ขั้นตอนที่ 2 SHA-256: d590bd375d95e4ac072b7ebc1fc4489bcaf5f20a939e92486267aa398bcf1e5d
3. ชั้นที่สอง: ถอดรหัส AES-128-GCM สำหรับ Bun bootloader และโหลดหลัก
รหัส Stage 2 ที่ถอดรหัสจาก ROT/Caesar ใช้ Node.js crypto.createDecipheriv เพื่อดีคริปต์ด้วย AES-128-GCM (Advanced Encryption Standard - Galois/Counter Mode) และตั้งแท็กการรับรองผ่าน setAuthTag เป้าหมายของการถอดรหัสคือสองส่วนประกอบถัดไป—ตัวเริ่มต้นสภาพแวดล้อม Bun และโหลดอันตรายหลัก
ในนั้น ตัวนำร่องสภาพแวดล้อม Bun มีหน้าที่ตรวจจับ ระบุ หรือเตรียมสภาพแวดล้อม Bun เพื่อให้รหัสถัดไปสามารถดำเนินการผ่าน Bun ได้; ส่วนโหลดที่เป็นอันตรายหลักคือส่วนหลักของโซ่การโจมตี ซึ่งรวมถึงความสามารถในการโจมตีหลักๆ เช่น การรวบรวมข้อมูลประจำตัว การแพร่กระจายผ่าน GitHub/npm การคงอยู่อย่างต่อเนื่อง การต่อต้านการป้องกัน และการถอดรหัสทรัพยากรที่ฝังอยู่
ตัวอย่างทั้งสามใช้คีย์ AES-128-GCM ตัวแปรเริ่มต้น และแท็กการรับรองที่แตกต่างกันในการเข้ารหัสส่วนประกอบทั้งสอง แต่ค่า SHA-256 ของตัวนำร่องสภาพแวดล้อม Bun หลังถอดรหัสทั้งสามตัวคือ ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6 และค่า SHA-256 ของภาระงานอันตรายหลักทั้งสามตัวคือ 0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35 ซึ่งแสดงให้เห็นว่าผู้โจมตีได้เปลี่ยนพารามิเตอร์การห่อชั้นนอกในแพ็กเกจ npm ที่แตกต่างกัน แต่ใช้ซ้ำชุดส่วนประกอบอันตรายหลักเดียวกัน
ถอดรหัสแล้ว Stage 2 จะเขียนโหลดที่เป็นอันตรายหลักไปยัง /tmp แล้วดำเนินการผ่าน Bun สุดท้ายจึงลบไฟล์ชั่วคราว ตรรกะที่แท้จริงที่ได้รับจากการกู้คืนตัวอย่างทั้งสามมีดังนี้:
ดังนั้น รูปแบบไฟล์ชั่วคราวที่สามารถตรวจสอบได้ในตัวอย่างทั้งสามคือ:
/tmp/p.js
ขนาดของตัวนำร่องสภาพแวดล้อม Bun คือ 898 ไบต์ แฮชของตัวอย่างทั้งสามตรงกันทั้งหมด:
ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6
ตัวนำร่องสภาพแวดล้อม Bun ประกอบด้วยตรรกะเช่น child_process.execSync, fs.existsSync, fs.mkdtempSync, fs.chmodSync, os.platform(), os.arch(), getBunPath() เพื่อระบุหรือเตรียมสภาพแวดล้อมการทำงานของ Bun กล่าวอีกนัยหนึ่ง ขั้นตอนที่ 2 ไม่ได้สมมติเพียงว่า Bun ติดตั้งแบบทั่วไปในระบบ; ในเส้นทางที่ไม่ใช่สภาพแวดล้อมการทำงานของ Bun มันจะโหลดตัวนำร่องสภาพแวดล้อม Bun ก่อน แล้วเรียก Bun ผ่าน getBunPath() เพื่อดำเนินการโหลดความเสี่ยงหลัก
4. ระดับที่สาม: ตารางสตริงของ obfuscator.io
ภาระงานที่ถอดรหัสได้ไม่ใช่ JavaScript แบบข้อความธรรมดาที่อ่านได้ทันที แต่ยังคงถูกทำให้สับสนด้วยรูปแบบของ obfuscator.io โดยใช้ตารางสตริง ซึ่งจะรวบรวมสตริงจำนวนมากไว้ในอาร์เรย์ และใช้การอ้างอิงแบบรันไทม์และตรรกะการหมุนเพื่อคืนค่ากลับ ทำให้นักวิเคราะห์ไม่สามารถค้นหา API, เส้นทาง และชื่อการตั้งค่าสำคัญถัดไปได้ หากยังไม่ได้คืนค่าตารางสตริงให้สมบูรณ์
5. ชั้นที่สี่: B5 การเข้ารหัสสตริงที่กำหนดเอง
หลังจากถอดรหัสตารางสตริงของ obfuscator.io แล้ว ยังคงมีการเข้ารหัสสตริงแบบกำหนดเองของ B5 อยู่ในโหลดที่เป็นอันตรายหลัก ได้ยืนยันพารามิเตอร์ดังต่อไปนี้:
- KDF: PBKDF2 (Password-Based Key Derivation Function 2)
- ฟังก์ชันแฮช: SHA-256
- จำนวนการวนซ้ำ: 200000
- ความยาวคีย์: 32 ไบต์
- จำนวนรอบการถอดรหัส: 3
- รหัสผ่าน: ba2c6ddb3672bdd6a611e6850b4f700b52aed3dab2f1b3d5f8c839d4a157a709
- salt: 5b26508dc0f1075a7c0b4d8aa464487e
ผลหลังถอดรหัสคือ:
ในนั้น หลังจากถอดรหัส B5 จะสามารถมองเห็นสตริงข้อความชัดเจนหลายประเภท โปรดสังเกตว่า สตริงบางส่วนเดิมอยู่ในตารางสตริงของ obfuscator.io และจะสามารถค้นหาด้วย grep ได้โดยตรงเท่านั้น เมื่อเสร็จสิ้นขั้นตอนทั้งสองขั้นตอนคือ “การแทนที่ตารางสตริง + การถอดรหัส B5”
6. ชั้นฝังเพิ่มเติม: AES-256-GCM + gzip
โหลดอันตรายหลักยังรวมถึงทรัพยากรที่ฝังไว้ซึ่งถูกเข้ารหัสด้วย AES-256-GCM และบีบอัดด้วย gzip ตรรกะการกู้คืนใช้:
ทรัพยากรที่ถูกถอดรหัสแล้วจัดหมวดหมู่ตามฟังก์ชันเป็นสามประเภท:
การอ่านหน่วยความจำข้ามแพลตฟอร์ม:
ทรัพยากรประเภทนี้ใช้สำหรับอ่านหน่วยความจำของกระบวนการที่กำลังทำงานอยู่ คีย์หรือโทเค็นในไฟล์ทั่วไปยังสามารถค้นพบได้โดยการตรวจสอบไฟล์ แต่ CI/CD Runner หรือเครื่องมือพัฒนาจะเก็บค่าที่ละเอียดอ่อนบางอย่างไว้ชั่วคราวในหน่วยความจำขณะทำงาน ผู้โจมตีได้ฝังสคริปต์อ่านหน่วยความจำสำหรับแพลตฟอร์ม Linux, Windows และ macOS เพื่อพยายามดึง secret ที่ปรากฏชั่วคราวเหล่านี้จากหน่วยความจำของกระบวนการในระบบต่างๆ

การตั้งค่าแบบถาวร:
ทรัพยากรประเภทนี้ใช้เพื่อ “วางจุดกระตุ้นหลังประตู” กล่าวคือ แม้กระบวนการติดตั้ง npm เริ่มต้นจะเสร็จสิ้นแล้ว ผู้โจมตียังต้องการให้รหัสที่เป็นอันตรายทำงานอีกครั้งเมื่อผู้พัฒนาเปิดโครงการ khởi độngตัวแก้ไขรหัส เข้าสู่เซสชัน Claude Code หรือเมื่อระบบล็อกอินใหม่ ดังนั้นทรัพยากรเหล่านี้จึงมุ่งเป้าไปที่การตั้งค่าระดับโครงการและกลไกเริ่มต้นอัตโนมัติระดับผู้ใช้: การตั้งค่าระดับโครงการมีความซ่อนเร้นมากกว่า ขณะที่บริการระดับระบบเหมาะสำหรับการรันระยะยาว

C2 กับการแพร่กระจาย:
ทรัพยากรที่ฝังไว้เหล่านี้ใช้สำหรับการควบคุมเส้นทางถัดไปและการโอน secrets ของรีโพสิทอรี หลังจาก YZ ถอดรหัสแล้วจะเป็น GitHub commit search monitor ซึ่งจะค้นหาข้อความ commit ที่มีรูปแบบ firedalazer . เป็นระยะๆ ตรวจสอบลายเซ็นแล้วดาวน์โหลดและรันเนื้อหา Python จากระยะไกล ส่วน zZ หลังจากถอดรหัสแล้วจะเป็นเทมเพลต GitHub Actions workflow ชื่อ Run Copilot ซึ่งจะเขียน ${{ toJSON(secrets) }} ลงในไฟล์ format-results.txt และอัปโหลดเป็น artifact ตัวแรกให้บริการเส้นทางการรับ/รันงานถัดไป ส่วนตัวที่สองให้เทมเพลตในการโอน secrets ของรีโพสิทอรีผ่าน GitHub Actions artifact; การฉีด การรัน และการดาวน์โหลด artifact จะถูกดำเนินการโดยตรรกะ GitHub API ที่มาพร้อมกับโหลดหลัก

การวิเคราะห์ความสามารถของโหลดอันตรายหลัก
หลังจากดำเนินการถอดรหัสหลายชั้น ตัวอย่างสุดท้ายจะปล่อยและดำเนินการโหลดอันตรายหลัก การวิเคราะห์ทั้งหมดด้านล่างนี้เน้นที่โมดูลโหลดอันตรายหลัก โดยแยกออกเป็นห้าขั้นตอน: การรับข้อมูล การส่งออกข้อมูล การแพร่กระจาย การคงอยู่อย่างต่อเนื่อง และการต่อต้าน
การอ่านหน่วยความจำของ GitHub Actions Runner:
ตัวอย่างมีสคริปต์อ่านหน่วยความจำสำหรับแพลตฟอร์ม Linux, Windows และ macOS พร้อมความสามารถในการดัมพ์ข้ามแพลตฟอร์ม โดยการดำเนินการบน Linux ใช้การอ่าน /proc//maps และ /proc//mem ของกระบวนการเป้าหมายเพื่อดึงหน่วยความจำ:
ตรรกะการกระตุ้นอย่างแข็งขันของโหลดอันตรายหลักมุ่งเป้าไปที่ Linux runner ของ GitHub Actions: เมื่อ GITHUB_ACTIONS === "true" และ RUNNER_OS === "Linux" โค้ดจะค้นหากระบวนการ Runner.Worker และดัมพ์หน่วยความจำ จากนั้นดึง secrets ที่ถูกซ่อนในรูปแบบ "":{"value":"","isSecret":true} จากการดัมพ์ แม้ว่าเส้นทางการรวบรวมอย่างแข็งขันที่ยืนยันได้ในตัวอย่างทั้งสามจะมุ่งเน้นที่ Linux runner แต่สคริปต์สำหรับสามแพลตฟอร์มได้ถูกฝังไว้แล้ว
2. การรวบรวมข้อมูลรับรองของนักพัฒนาในสภาพแวดล้อมหลายคลาวด์:
โหลดไวรัสหลักประกอบด้วยโมดูลการรวบรวมข้อมูลรับรองอย่างเป็นระบบ ครอบคลุมผู้ให้บริการคลาวด์ สภาพแวดล้อม CI การตั้งค่าของนักพัฒนาในท้องถิ่น GitHub CLI ตัวจัดการรหัสผ่าน และไฟล์กระเป๋าเงิน
เป้าหมายการรวบรวมข้อมูลรับรองจากผู้ให้บริการคลาวด์คือ:

โมดูล AWS ยังรวมตรรกะที่เกี่ยวข้องกับ ECS/IMDS (Instance Metadata Service)/STS WebIdentity
การรวบรวมข้อมูลรับรองของนักพัฒนาในท้องถิ่นครอบคลุมเป้าหมายต่อไปนี้:

ลอจิกของตัวจัดการรหัสผ่านถูกดำเนินการในโค้ดแหล่งที่มาในรูปแบบของอาร์เรย์ runCommand(command, args) แทนการเชื่อมสตริง shell
โมดูลการรวบรวมข้อมูลประจำตัวเหล่านี้ครอบคลุมเป้าหมายหลากหลายตั้งแต่แพลตฟอร์มคลาวด์จนถึงอุปกรณ์ของนักพัฒนา; ข้อมูลที่ละเอียดอ่อนที่รวบรวมได้จะถูกส่งออกผ่านกลไกต่อไปนี้
3. GitHub API ถูกเปิดเผยและ dead-drop:
โหลดที่เป็นอันตรายหลักใช้ GitHub API เป็นช่องทางหลักในการส่งข้อมูลออก คำขอปลอมแปลง User-Agent เป็น python-requests/2.31.0 และหลังจากตรวจสอบ token ผ่าน x-oauth-scopes (ต้องมี repo, public_repo หรือ workflow) จะดำเนินการส่งข้อมูลออก: สร้าง repository (description ตั้งค่าคงที่เป็น Miasma: The Spreading Blight) และเขียนข้อมูลที่ขโมยมาซึ่งถูกเข้ารหัสแบบ base64 ผ่าน PUT /repos///contents/results/
นอกจากนี้ โหลดยังใช้กลไก dead-drop ที่อิงจากการค้นหา commit บน GitHub โดยการค้นหา marker "thebeautifulmarchoftime" (หรือ "thebeautifulsnadsoftime") เพื่อรับคำสั่ง C2:
let result = await X9("thebeautifulmarchoftime ", xZ);
ทรัพยากรฝังตัว YZ.bin เป็นตัวติดตาม GitHub commit แบบอิสระ ที่สแกนหาข้อความ commit รูปแบบ firedalazer . ทุกๆ 3600 วินาที หลังจากตรวจสอบลายเซ็นแล้ว จะดาวน์โหลดและรันเนื้อหา Python จากระยะไกล ซึ่งสร้างช่องทางการควบคุมต่อเนื่องที่แยกจากช่องทางหลัก
รหัสแหล่งที่มายังรวมถึงการตั้งค่าตัวส่ง HTTP POST ที่มีจุดหมายปลายทางเป็น api.anthropic.com และ v1/api ฟิลด์ noop ของการตั้งค่านี้ถูกตั้งค่าเป็น true ซึ่งหมายความว่าในกรณีที่ไม่มีการเปลี่ยนแปลงจากภายนอก ตัวส่งนี้จะไม่ส่งคำขอเครือข่ายจริง ดังนั้นการวิเคราะห์แบบคงที่สามารถยืนยันได้เฉพาะโครงสร้างโค้ดเท่านั้น ไม่สามารถพิสูจน์ได้ว่ามีพฤติกรรมการส่งข้อมูลไปยัง Anthropic API ที่ใช้งานอยู่
4. การติดเชื้อในรีโพสิทอรี GitHub และ Workflow:
โหลดที่เป็นอันตรายหลักสามารถดำเนินการวัตถุ git ของรีโพสิทอรีผ่าน GitHub REST / GraphQL API:

งานที่มีเจตนาไม่ดีที่สร้างขึ้นภายใต้ชื่อ release ขอสิทธิ์ id-token: write เพื่อแลกเปลี่ยนโทเค็นการเผยแพร่ npm ผ่านเส้นทาง OIDC (OpenID Connect) ตัวแปรสภาพแวดล้อมและอินเทอร์เฟซของเส้นทาง OIDC คือ ACTIONS_ID_TOKEN_REQUEST_TOKEN และ ACTIONS_ID_TOKEN_REQUEST_URL โดยตั้งค่า audience เป็น npm:registry.npmjs.org สามารถยืนยันได้ในระดับซอร์สโค้ดว่า payload มีความสามารถในการแทรกงาน workflow เข้าไปในรีโพสิทอรี GitHub และใช้ OIDC / npm trusted publishing เพื่อขอสิทธิ์การเผยแพร่
นอกจากวิธีการฉีด workflow ผ่าน git refs ที่กล่าวถึงข้างต้น โหลดยังฝังกลไกการขนส่ง secrets ที่ซ่อนเร้นยิ่งขึ้น: workflow GitHub Actions ที่ปลอมตัวเป็น Run Copilot จะเขียน ${{ toJSON(secrets) }} ลงในไฟล์ format-results.txt และอัปโหลด artifact แทนการเขียน secrets โดยตรงลงในเนื้อหาของรีโพสิทอรี วิธีนี้มุ่งเน้นการขนส่งข้อมูลผ่านผลลัพธ์ของการรัน workflow ซึ่งการตรวจสอบ diff ของโค้ดตามปกติอาจไม่สามารถมองเห็นเนื้อหา secrets ที่ส่งออกสุดท้ายได้
5. รันงาน流程 Copilot ผ่าน artifact ย้าย secrets:
ทรัพยากรที่ฝังไว้ zZ.bin เป็น workflow ของ GitHub Actions ที่ปลอมตัวเป็น Copilot ซึ่งเขียน ${{ toJSON(secrets) }} ลงในไฟล์ format-results.txt และอัปโหลดเป็น artifact
พฤติกรรม GitHub API ที่เกี่ยวข้องรวมถึง: สร้าง/อัปเดต branch ชั่วคราว → เขียน blob ของ workflow → รอการรัน workflow → ดาวน์โหลดไฟล์ zip ของ artifact → อ่านไฟล์ format-results.txt → ลบ workflow run และ branch ชั่วคราว คำสำคัญที่เกี่ยวข้องได้แก่ Run Copilot, VARIABLE_STORE, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml
6. npm การแพร่กระจายด้วยตัวเอง:
โหลดที่เป็นอันตรายหลักมีเส้นทางการเผยแพร่/แพร่กระจาย npm สองเส้นทางที่แยกจากกัน
เส้นทาง npm token: โหลดข้อมูลผ่าน GET /-/npm/v1/tokens เพื่อระบุ npm token ของผู้ใช้ปัจจุบัน กรอง token ที่มี bypass_2fa === true และมีสิทธิ์เขียนแพ็กเกจ ใช้ token เหล่านี้เพื่อเผยแพร่อัตโนมัติ bypass_2fa เป็นฟิลด์เมตาดาต้าของ token ไม่ใช่พารามิเตอร์ของ publish body
เส้นทาง GitHub Actions OIDC: อ่านตัวแปรสภาพแวดล้อม ACTIONS_ID_TOKEN_REQUEST_TOKEN และ ACTIONS_ID_TOKEN_REQUEST_URL ขอ OIDC token ที่มี audience เป็น npm:registry.npmjs.org แล้วแลกเปลี่ยนสิทธิ์การเผยแพร่ผ่านอินเทอร์เฟซ OIDC token exchange ของ npm
ขั้นตอนการปนเปื้อนไฟล์ tarball คือถอดแพ็กเกจ → เขียนไฟล์ index.js ที่มีอันตราย → แก้ไข package.json:
ที่นี่แบ่งออกเป็นสองประเภทของจุดเริ่มต้น: ตัวอย่างที่อัปโหลดท้องถิ่นสามชุดใช้ preinstall: "node index.js" — ในกรณีนี้ ไม่จำเป็นต้องติดตั้ง Bun ล่วงหน้าในการติดตั้งสภาพแวดล้อม เพราะการใช้ Node.js เป็นจุดเริ่มต้นจะซ่อนตัวได้ดีกว่า; ในขณะที่เมื่อแพร่กระจายเองเพื่อปนเปื้อนแพ็กเกจอื่นๆ จะเขียน preinstall: "bun run index.js" และเพิ่มการพึ่งพา bun — เนื่องจากตรรกะของโหลดที่เป็นอันตรายหลักพึ่งพา API ที่ให้โดยรันไทม์ของ Bun (เช่น Bun.gunzipSync และ Bun.file) ในสถานการณ์การแพร่กระจายเองจึงจำเป็นต้องรับประกันว่าสภาพแวดล้อมเป้าหมายมี Bun อยู่แล้ว
7. กลไกการบันทึกถาวร:
โหลดที่เป็นอันตรายหลักประกอบด้วยวิธีการยึดติดสี่แบบ ครอบคลุมไดเรกทอรีโปรเจกต์และการเริ่มต้นระบบ
Claude Code SessionStart hook: ฝังทรัพยากร S8.bin เพื่อเขียน SessionStart hook ลงใน .claude/settings.json โดยจะรัน node .claude/setup.mjs อัตโนมัติทุกครั้งที่เริ่มเซสชัน Claude Code โหลดที่เป็นอันตรายถูกเขียนลงใน .claude/setup.mjs และ .claude/index.js พร้อมกัน (เส้นทางถูกสร้างจาก ".claude/" + M0 โดยที่ M0 = "index.js")
งาน folderOpen ของ VS Code: ฝังทรัพยากร EZ.bin เพื่อเขียนงาน folderOpen ลงในไฟล์ .vscode/tasks.json และรันสคริปต์เดียวกันอัตโนมัติเมื่อเปิดโฟลเดอร์โปรเจกต์ที่ถูกโจมตี พร้อมเขียนไฟล์ .vscode/setup.mjs ด้วย
kitty-monitor (systemd / LaunchAgent): ฝังทรัพยากร RZ.bin เพื่อติดตั้งบริการแบบถาวร ไฟล์ถูกกระจายไปยัง /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service (Linux) และ ~/Library/LaunchAgents/com.user.kitty-monitor.plist (macOS) โหลดที่เป็นอันตรายสร้างไดเรกทอรี /tmp/kitty- เขียน YZ.bin (GitHub commit monitor) ลงใน cat.py แล้วติดตั้งผ่าน RZ.bin
gh-token-monitor (systemd / LaunchAgent): ติดตั้งบริการตรวจสอบ GitHub token โดยฝังทรัพยากร jZ.bin ไฟล์ถูกจัดเก็บไว้ที่ /.local/bin/gh-token-monitor.sh, /.config/gh-token-monitor/ และเส้นทาง systemd / LaunchAgent ที่เกี่ยวข้อง ตัวตรวจสอบจะตรวจจับว่า GitHub token ตอบกลับด้วยรหัสสถานะ 40x หรือไม่ และวัดข้อมูลเมตาของแพ็กเกจ npm @cap-js/openapi@1.4.1 ว่าผิดปกติหรือไม่ เมื่อเกิดเหตุการณ์ จะเรียกใช้ handler:
นี่หมายความว่าเมื่อ monitor สังเกตเห็นว่า GitHub API ตอบกลับด้วยรหัสสถานะ 40x เช่น token ถูกเพิกถอน หมดอายุ หรือสถานะสิทธิ์ผิดปกติ สคริปต์ที่เป็นอันตรายจะดำเนินการ handler ที่ส่งเข้ามา ในตัวอย่างสามตัวอย่างจากบทความนี้ handler ที่ถูกกู้คืนคือ rm -rf ~/; rm -rf ~/Documents เมื่อจัดการสถานการณ์นี้ ห้ามเพิกถอน token โดยตรงบนโฮสต์ที่อาจยังคงรัน payload อยู่—ควรแยกโฮสต์ออกก่อน ลบรายการที่ยังคงอยู่และกระบวนการที่กำลังรันอยู่ แล้วจึงเปลี่ยนข้อมูลประจำตัวจากสภาพแวดล้อมที่สะอาด
8. Harden-Runner / StepSecurity ต่อสู้:
โหลดอันตรายหลักมีการฝังตรรกะในการตรวจจับและทำลาย StepSecurity Harden-Runner โดยข้ามการป้องกัน CI/CD ผ่านขั้นตอนต่อไปนี้:
- ตรวจสอบว่า Docker socket /var/run/docker.sock ใช้งานได้หรือไม่;
- แสดงคอนเทนเนอร์ Docker ที่ตรงกับคีย์เวิร์ด harden-runner หรือ stepsecurity ในชื่อหรือภาพ
- ยกเลิกคอนเทนเนอร์ที่ตรงกันผ่าน POST /containers//kill;
- สร้างคอนเทนเนอร์ Alpine แบบมีสิทธิ์พิเศษ โดยแก้ไขไฟล์ sudoers เป็น runner ALL=(ALL) NOPASSWD:ALL;
- เขียนการแก้ไขชื่อโดเมนที่เกี่ยวข้องกับ StepSecurity ลงใน /etc/hosts อย่างไม่ถูกต้อง;
- เขียนทับ /etc/resolv.conf ด้วย 8.8.8.8 และ 1.1.1.1
ตรรกะการต่อต้านนี้แสดงให้เห็นว่าตัวอย่างได้รับการปรับให้เหมาะกับสภาพแวดล้อม CI/CD ที่ได้รับการป้องกันโดย StepSecurity
9. EDR / การตรวจจับผลิตภัณฑ์ด้านความปลอดภัย การวิเคราะห์สภาพแวดล้อม และการหลีกเลี่ยง:
โหลดไวรัสหลักตรวจจับชื่อกระบวนการและเส้นทางการติดตั้งของผลิตภัณฑ์ EDR (Endpoint Detection and Response) / ความปลอดภัยหลายตัว:

โหลดยังรวมตรรกะการหลีกเลี่ยงภูมิภาค: ตรวจจับตัวแปรสภาพแวดล้อม LC_ALL, LC_MESSAGES, LANGUAGE, LANG หลังจากแปลงเป็นตัวพิมพ์เล็ก หากเริ่มต้นด้วย ru จะข้ามการดำเนินการ การระบุสภาพแวดล้อม CI รองรับ GitHub Actions, GitLab CI, Travis CI, CircleCI, Jenkins, AWS CodeBuild, Buildkite, AppVeyor, Bitbucket, Drone, TeamCity, Cirrus CI เป็นต้น ป้ายสถานะที่ใช้ในช่วงรันรวมถึง tmp.0987654321.lock, __IS_DAEMON (ป้ายกำกับกระบวนการเดโมนที่แยกตัวออก), SKIP_DOMAIN (ข้ามเส้นทาง sender ของโดเมน), /tmp/kitty-*, cat.py และ /var/tmp/.gh_update_state
Impact Analysis
จากความสามารถของซอร์สโค้ด ผลกระทบของตัวอย่างทั้งสามนี้ไม่ได้จำกัดอยู่เพียงการดำเนินการแบบครั้งเดียวในขั้นตอนการติดตั้งผ่าน npm ความเสี่ยงที่แท้จริงสามารถแบ่งออกเป็นสี่ระดับ:
ระดับโฮสต์ของนักพัฒนา ตัวอย่างจะรวบรวมตัวแปรสภาพแวดล้อม .npmrc .pypirc คีย์ SSH การตั้งค่า Docker .env โทเค็น GitHub CLI ข้อมูลผู้จัดการรหัสผ่าน และไฟล์กระเป๋าเงิน และรักษาความสามารถในการกระตุ้นในภายหลังผ่าน Claude Code VS Code systemd user service หรือ macOS LaunchAgent
ในระดับ CI/CD Runner ตัวอย่างจะตรวจจับ GitHub Actions Linux runner อ่านหน่วยความจำของกระบวนการ Runner.Worker และดึงข้อมูลลับที่ถูกซ่อนไว้; นอกจากนี้ยังมีตรรกะต่อต้าน StepSecurity Harden-Runner เพื่อพยายามทำลายหรือหลีกเลี่ยงส่วนประกอบป้องกัน CI/CD
ในระดับองค์กรและรีโพสิทอรีของ GitHub ตัวอย่างสามารถใช้ GitHub API เพื่อสร้างรีโพสิทอรี เขียนข้อมูลลงใน contents/results/ จัดการ git refs/blobs/trees/commits แทรก workflow ที่เป็นอันตราย และถ่ายโอน secrets ผ่านการรัน Copilot workflow + artifact
ในระดับการแพร่กระจายของระบบนิเวศ npm ตัวอย่างสามารถกรอง token npm ที่มีสิทธิ์เขียน package และ bypass_2fa === true หรือใช้เส้นทาง GitHub Actions OIDC / npm trusted publishing เพื่อแลกเปลี่ยนสิทธิ์การเผยแพร่ จากนั้นดาวน์โหลด tarball เป้าหมาย แทรก loader ที่เป็นอันตราย แก้ไข preinstall เพิ่มการพึ่งพา Bun ปรับเวอร์ชัน patch และเผยแพร่ เพื่อสร้างโซ่การแพร่กระจายภายใน npm
Summary
หลักฐานรหัสแหล่งที่มาจากตัวอย่างสามชุดแสดงว่าแพ็กเกจที่เป็นอันตรายครั้งนี้ไม่ใช่เพียงสคริปต์ขโมยข้อมูลในระหว่างการติดตั้ง แต่เป็นการรวมกันของ loader หลายขั้นตอนและ implant ที่สมบูรณ์: ชั้นนอกถูกสุ่มแบบเฉพาะของแต่ละแพ็กเกจ ขณะที่ตัวนำร่องสภาพแวดล้อม Bun และโหลดหลักที่เป็นอันตรายมีความสอดคล้องกัน; implant หลักครอบคลุมหลายขั้นตอน เช่น การเก็บข้อมูลการรับรองความถูกต้อง การดึง CI secret การแพร่กระจายผ่าน GitHub/npm การคงอยู่อย่างต่อเนื่อง และการต่อต้านการป้องกัน
การออกแบบช่องทางเข้าที่ซ่อนเร้นอย่างสูง ผู้โจมตีไม่ได้ฝังตรรกะที่เป็นอันตรายในโค้ดธุรกิจ แต่ติดตั้ง loader ที่ถูกเข้ารหัสไว้ในสคริปต์ชีวิตของ npm loader นี้มีหน้าที่หลักในการถอดรหัสและดำเนินการโหลดที่ฝังอยู่ ทำให้การตรวจสอบซอร์สโค้ดธุรกิจเพียงอย่างเดียวยากที่จะตรวจพบความสามารถที่แท้จริง
โซ่การถอดรหัสที่ซ้อนกันหลายชั้น ภาระงานที่เป็นอันตรายผ่านการเข้ารหัสแบบอาร์เรย์ตัวเลข + การแทนที่ตัวอักษร ROT, การเข้ารหัส AES-128-GCM, การทำให้สับสนโดย obfuscator.io, การเข้ารหัสสตริงเฉพาะตัวของ B5, และชั้นการฝังด้วย AES-256-GCM + gzip รวมทั้งหมดห้าชั้น คีย์หรือพารามิเตอร์ของแต่ละชั้นสามารถเปลี่ยนแปลงได้อย่างอิสระในแพ็กเกจต่างๆ ทำให้การตรวจจับแบบกลุ่มตามลักษณะคงที่ยากยิ่งขึ้น
ความสามารถในการโจมตีระดับองค์กรอย่างสมบูรณ์ implant นี้มีความสามารถในการอ่านหน่วยความจำของ GitHub Actions Runner, รวบรวมข้อมูลรับรองจากหลายคลาวด์และในท้องถิ่น, ส่งข้อมูลผ่าน GitHub API และ dead-drop, ติดเชื้อ repository และ workflow ของ GitHub, แพร่กระจายตัวเองผ่าน npm, การคงอยู่อย่างต่อเนื่อง และการต่อต้านการป้องกัน จากโครงสร้างโค้ดต้นฉบับ ดูเหมือนว่ามันมีเส้นทางโค้ดที่สามารถเริ่มต้นจากการติดตั้งจุดเดียวแล้วแพร่กระจายไปยัง repository, CI/CD และห่วงโซ่การเผยแพร่ npm ขอบเขตการแพร่กระจายที่แท้จริงยังต้องยืนยันร่วมกับบันทึกการติดตั้ง การตรวจสอบ repository และข้อมูลการวัดจากระบบ
จากหลักฐานรหัสต้นทางสามารถยืนยันได้ว่า: ตัวอย่างทั้งสามถูกกระตุ้นอัตโนมัติผ่าน preinstall และถอดรหัสเพื่อเรียกใช้ main implant เดียวกัน แต่ไม่สามารถพิสูจน์ได้จากตัวอย่าง tgz ทั้งสามนี้ว่าสิทธิ์เริ่มต้นในเหตุการณ์จริงได้มาอย่างไร
คำแนะนำในการจัดการ
- ตรวจสอบและลบเวอร์ชันที่เป็นอันตรายออกจากความพึ่งพาของโปรเจกต์ ไฟล์ล็อก แคชเรจิสทรีส่วนตัว และแคชการสร้าง
- ตรวจสอบว่าในบันทึกการติดตั้งมีคำสั่ง preinstall, node index.js, bun run, /tmp/p*.js, tmp.0987654321.lock หรือไม่
- อย่าเพิกถอนโทเค็นโดยตรงบนโฮสต์ที่ยังอาจรัน payload อยู่ แนะนำให้แยกโฮสต์ที่ถูกโจมตีออกก่อน ลบกระบวนการที่กำลังรันและรายการที่ยังคงอยู่อย่างถาวร จากนั้นจึงเปลี่ยนโทเค็นที่เกี่ยวข้องกับ GitHub, npm, ข้อมูลประจำตัวของคลาวด์, Kubernetes, Vault, SSH, Docker registry และตัวจัดการรหัสผ่านจากสภาพแวดล้อมที่สะอาด
- ตรวจสอบรีพอสิทอรี GitHub สำหรับ branch, commit, workflow, artifact และรีพอสิทอรีใหม่ล่าสุด โดยเน้นที่คีย์เวิร์ดเช่น Run Copilot, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml, OIDC_PACKAGES
- ตรวจสอบว่ามีการเพิ่มหรือแก้ไขไดเรกทอรีโปรเจกต์หรือไม่: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, .vscode/setup.mjs
- ตรวจสอบการจัดเก็บถาวรระดับผู้ใช้: /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service, ~/Library/LaunchAgents/com.user.kitty-monitor.plist, ไฟล์ที่เกี่ยวข้องกับ gh-token-monitor
- ตรวจสอบประวัติการเผยแพร่ npm เพื่อยืนยันว่ามีการเผยแพร่เวอร์ชันแพตช์ที่ไม่ได้รับอนุญาตหรือไม่; พร้อมทั้งตรวจสอบเมตาดาต้าของ npm token โดยเน้นที่ token ที่สามารถข้าม 2FA (Two-Factor Authentication) และมีสิทธิ์เขียนแพ็กเกจ
- ดำเนินการตรวจสอบความสมบูรณ์ของผลิตภัณฑ์ที่สร้างขึ้นในสภาพแวดล้อมที่ปนเปื้อน
IOC
ไฟล์ที่เป็นอันตราย
ชื่อไฟล์: redhat-cloud-services-frontend-components-config-6.11.3.tgz MD5: 633ad8849a59e2bfb7a0fe589e816a07 SHA1: 675294612f455fe6a9acb195f0cbe3687d8e2e34 SHA256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060
ชื่อไฟล์: redhat-cloud-services-types-3.6.1.tgz MD5: 9e6c5af01438b52c9a411686c1f1b8ff SHA1: 88d098c8d96e9ae17550e9798c3b62c420464b8c SHA256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558
ชื่อไฟล์: redhat-cloud-services-rule-components-4.7.2.tgz MD5: f1ffdbf5e639899f26a6ebab2eec408d SHA1: f3c5c21274045ae02fef11e931de6dcf8462a067 SHA256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f
SHA256
ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6
0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35
การพึ่งพาอย่างไม่เหมาะสม
npm:@redhat-cloud-services/topological-inventory-client@3.0.10
npm:@redhat-cloud-services/topological-inventory-client@3.0.11
npm:@redhat-cloud-services/topological-inventory-client@3.0.13
npm:@redhat-cloud-services/compliance-client@4.0.3
npm:@redhat-cloud-services/compliance-client@4.0.4
npm:@redhat-cloud-services/compliance-client@4.0.6
npm:@redhat-cloud-services/rbac-client@9.0.3
npm:@redhat-cloud-services/rbac-client@9.0.4
npm:@redhat-cloud-services/rbac-client@9.0.6
npm:@redhat-cloud-services/insights-client@4.0.4
npm:@redhat-cloud-services/insights-client@4.0.5
npm:@redhat-cloud-services/insights-client@4.0.7
npm:@redhat-cloud-services/frontend-components@7.7.2
npm:@redhat-cloud-services/frontend-components@7.7.3
npm:@redhat-cloud-services/frontend-components@7.7.5
npm:@redhat-cloud-services/frontend-components-utilities@7.4.1
npm:@redhat-cloud-services/frontend-components-utilities@7.4.2
npm:@redhat-cloud-services/frontend-components-utilities@7.4.4
npm:@redhat-cloud-services/remediations-client@4.0.4
npm:@redhat-cloud-services/remediations-client@4.0.5
npm:@redhat-cloud-services/remediations-client@4.0.7
npm:@redhat-cloud-services/frontend-components-notifications@6.9.2
npm:@redhat-cloud-services/frontend-components-notifications@6.9.3
npm:@redhat-cloud-services/frontend-components-notifications@6.9.5
npm:@redhat-cloud-services/patch-client@4.0.4
npm:@redhat-cloud-services/patch-client@4.0.5
npm:@redhat-cloud-services/patch-client@4.0.7
npm:@redhat-cloud-services/host-inventory-client@5.0.3
npm:@redhat-cloud-services/host-inventory-client@5.0.4
npm:@redhat-cloud-services/host-inventory-client@5.0.6
npm:@redhat-cloud-services/rule-components@4.7.2
npm:@redhat-cloud-services/rule-components@4.7.3
npm:@redhat-cloud-services/rule-components@4.7.5
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.2
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.4
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.6
npm:@redhat-cloud-services/notifications-client@6.1.4
npm:@redhat-cloud-services/notifications-client@6.1.5
npm:@redhat-cloud-services/notifications-client@6.1.7
npm:@redhat-cloud-services/sources-client@3.0.10
npm:@redhat-cloud-services/sources-client@3.0.11
npm:@redhat-cloud-services/sources-client@3.0.13
npm:@redhat-cloud-services/integrations-client@6.0.4
npm:@redhat-cloud-services/integrations-client@6.0.5
npm:@redhat-cloud-services/integrations-client@6.0.7
npm:@redhat-cloud-services/frontend-components-config@6.11.3
npm:@redhat-cloud-services/frontend-components-config@6.11.4
npm:@redhat-cloud-services/frontend-components-config@6.11.6
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.2
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.3
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.5
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.1
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.2
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.4
npm:@redhat-cloud-services/frontend-components-remediations@4.9.2
npm:@redhat-cloud-services/frontend-components-remediations@4.9.3
npm:@redhat-cloud-services/frontend-components-remediations@4.9.5
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.1
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.2
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.4
npm:@redhat-cloud-services/javascript-clients-shared@2.0.8
npm:@redhat-cloud-services/javascript-clients-shared@2.0.9
npm:@redhat-cloud-services/javascript-clients-shared@2.0.11
npm:@redhat-cloud-services/quickstarts-client@4.0.11
npm:@redhat-cloud-services/quickstarts-client@4.0.12
npm:@redhat-cloud-services/quickstarts-client@4.0.14
npm:@redhat-cloud-services/config-manager-client@5.0.4
npm:@redhat-cloud-services/config-manager-client@5.0.5
npm:@redhat-cloud-services/config-manager-client@5.0.7
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.1
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.2
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.4
npm:@redhat-cloud-services/entitlements-client@4.0.11
npm:@redhat-cloud-services/entitlements-client@4.0.12
npm:@redhat-cloud-services/entitlements-client@4.0.14
npm:@redhat-cloud-services/tsc-transform-imports@1.2.2
npm:@redhat-cloud-services/tsc-transform-imports@1.2.4
npm:@redhat-cloud-services/tsc-transform-imports@1.2.6
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.1
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.2
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.4
npm:@redhat-cloud-services/frontend-components-testing@1.2.1
npm:@redhat-cloud-services/frontend-components-testing@1.2.2
npm:@redhat-cloud-services/frontend-components-testing@1.2.4
npm:@redhat-cloud-services/types@3.6.1
npm:@redhat-cloud-services/types@3.6.2
npm:@redhat-cloud-services/types@3.6.4
npm:@redhat-cloud-services/chrome@2.3.1
npm:@redhat-cloud-services/chrome@2.3.2
npm:@redhat-cloud-services/chrome@2.3.4
npm:@redhat-cloud-services/frontend-components-translations@4.4.1
npm:@redhat-cloud-services/frontend-components-translations@4.4.2
npm:@redhat-cloud-services/frontend-components-translations@4.4.4
npm:@redhat-cloud-services/vulnerabilities-client@2.1.8
npm:@redhat-cloud-services/vulnerabilities-client@2.1.9
npm:@redhat-cloud-services/vulnerabilities-client@2.1.11
