สรุปสั้น
ผู้โจมตีใช้บัญชี GitHub ของผู้ร่วมพัฒนา (contributor) ที่ถูกยึด เข้าไปลบและอัปโหลดไฟล์ดาวน์โหลดใหม่แทนที่ใน release เดิม 5 รุ่นของ OVHcloud CLI เครื่องมือบรรทัดคำสั่งของบริษัท OVHcloud ผู้ให้บริการคลาวด์รายใหญ่ของฝรั่งเศส เมื่อวันจันทร์ที่ 19 ตุลาคม 2569 ไฟล์ใหม่เป็นไบนารีที่ออกแบบมาขโมยความลับที่เก็บบนดิสก์ของเครื่องที่รัน ไฟล์ปลอมค้างอยู่บน GitHub นานสูงสุด 94 นาที ตั้งแต่ 12:47 ถึง 14:21 UTC และกระทบเฉพาะผู้ที่ติดตั้งหรืออัปเดตในช่วงเวลานั้นผ่านช่องทางที่ไม่ตรวจค่าแฮช บน macOS, Linux x86_64/arm64 หรือ Windows x86_64 ผู้โจมตียังแก้ไฟล์ checksums.txt ให้ค่าแฮชตรงกับไบนารีปลอมด้วย
ซอร์สโค้ด แท็ก release และไปป์ไลน์ build ของบริษัทไม่ถูกแตะต้อง ไบนารีปลอมเป็นเพียงการ go build จาก commit ที่ใหม่กว่า แล้วอัปโหลดทับลงใน release ที่เผยแพร่ระหว่างเมษายนถึงกันยายน ต้นเหตุคือ OVHcloud ไม่ได้เปิดใช้ฟีเจอร์ release immutability ของ GitHub ทำให้ใครที่มีสิทธิ์เขียน repository เปลี่ยนไฟล์ใน release เก่าได้โดยไม่ผ่าน CI/CD เลย ลูกค้ารายหนึ่งจับได้เพราะงาน CI ที่ตรึงค่า SHA-256 ล้มเหลว OVHcloud ลบไฟล์ปลอมและออก v0.16.0 แบบ immutable release ในเย็นวันเดียวกัน แต่ยังไม่เปิดเผยว่ามัลแวร์อ่านไฟล์ใด ส่งข้อมูลไปที่ไหน หรือมีผู้ดาวน์โหลดกี่ราย และยังไม่มีใครวิเคราะห์ตัวอย่างไบนารีปลอมได้ในที่สาธารณะ
รายละเอียดข่าว
เว็บไซต์ The Hacker News รายงานเมื่อวันที่ 20 ตุลาคม 2569 ว่า ใน release v0.15.0 ผู้โจมตีเปลี่ยนไฟล์ 6 ไฟล์ ได้แก่ archive สำหรับ macOS x86_64 และ arm64, Linux x86_64 และ arm64, Windows x86_64 และไฟล์ checksums.txt ไฟล์ 6 รายการเดียวกันนี้ถูกลบออกจาก v0.11.0 ถึง v0.14.0 แล้วเช่นกัน ส่วนรุ่นสำหรับ Linux i386, Windows i386, Windows arm64 และ WebAssembly ไม่ถูกแตะ OVHcloud ระบุว่า v0.11.0 ถึง v0.15.0 ถูกบุกรุก ส่วน v0.10.0 ปลอดภัย
ลูกค้าที่จับได้ใช้คำสั่ง go version -m ดึงข้อมูล build ออกจากไบนารี Linux arm64 ตัวใหม่โดยไม่ต้องรัน แล้วโพสต์ใน GitHub issue สาธารณะเมื่อเวลา 13:50 UTC เพราะ repository ไม่มีช่องทางรายงานแบบส่วนตัว OVHcloud ลบไฟล์ปลอมราวครึ่งชั่วโมงต่อมา และเผยแพร่ v0.16.0 เวลา 17:16 UTC ภายใต้บัญชี ovh-cds พร้อมแท็กที่ลงนาม นาย Octave Klaba ผู้ก่อตั้ง OVHcloud โพสต์บน X ว่าผู้ได้รับผลกระทบควรเปลี่ยนความลับทุกอย่างที่เก็บไว้บนดิสก์ และยอมรับในโพสต์ที่สองว่าปัญหาเกิดจากไม่ได้เปิดตัวเลือก immutability ซึ่งตอนนี้เปิดแล้ว บริษัทสัญญาว่าจะเผยแพร่ postmortem โดยละเอียดในอีกไม่กี่วัน
OpenSourceMalware ซึ่งสร้างไทม์ไลน์จากบันทึกฝั่งเซิร์ฟเวอร์ของ GitHub พบว่าการอัปโหลดมาจากบัญชีของผู้ร่วมพัฒนาที่เคยมีงานถูก merge ใน repository เอกสารของ OVHcloud แต่ไม่ได้เป็นสมาชิกสาธารณะขององค์กร และ workflow release ไม่ได้ทำงานเลยระหว่าง 16 ตุลาคมจนถึงการ push แท็ก v0.16.0 การตรวจเบื้องต้นไม่พบ repository อื่นได้รับผลกระทบ และ OVHcloud ยังไม่บอกว่าข้อมูลรับรองของบัญชีถูกขโมยไปอย่างไร

วิธีการโจมตี
ผู้ที่มีสิทธิ์เขียน repository บน GitHub สามารถลบไฟล์ที่แนบกับ release แล้วอัปโหลดไฟล์ใหม่ชื่อเดิมได้ โดย URL ดาวน์โหลดไม่เปลี่ยน เว้นแต่จะเปิด release immutability ซึ่ง GitHub เปิดให้ใช้ทั่วไปตั้งแต่ตุลาคม 2568 แต่ฟีเจอร์นี้ปกป้องเฉพาะ release ที่สร้างหลังเปิดใช้เท่านั้น ผู้โจมตีอาศัยช่องนี้วางไบนารีปลอมใน release เก่าที่ผู้ใช้ไว้วางใจ
ช่องทางที่ได้รับไฟล์ปลอม (ถ้าทำในช่วง 12:47-14:21 UTC บนแพลตฟอร์มที่ได้รับผลกระทบ):
- รันสคริปต์ติดตั้งทางการ
curl -fsSL https://raw.githubusercontent.com/ovh/ovhcloud-cli/main/install.sh | shซึ่งดาวน์โหลด archive ของ release ล่าสุดโดยไม่เคยตรวจค่าแฮช - ดาวน์โหลด archive จากหน้า release ของ 5 รุ่นที่ได้รับผลกระทบ
- งาน CI หรือขั้นตอน build ที่ดึง archive จาก URL ดาวน์โหลดโดยไม่ตรึงค่าแฮช
- รันคำสั่ง upgrade ในตัว CLI จาก v0.12.0, v0.13.0 หรือ v0.14.0 บน macOS หรือ Linux ที่ติดตั้งด้วยสคริปต์หรือด้วยมือ ซึ่งดาวน์โหลดและแทนที่ไบนารีโดยไม่ตรวจแฮช
ช่องทางที่ไม่ได้รับผลกระทบ: Homebrew (cask ตรึง SHA-256 เดิม จึงปฏิเสธไฟล์ที่แฮชไม่ตรง The Hacker News ตรวจประวัติ commit ของ tap แล้วไม่พบการเปลี่ยนแปลงระหว่าง cask v0.15.0 กับ v0.16.0) · go install หรือ build จากซอร์ส (แท็ก v0.15.0 ยังชี้ commit 760fd72) · Docker image (แท็ก latest ถูก push ครั้งสุดท้าย 21 กันยายน) · ผู้ที่ติดตั้งก่อน 12:47 UTC และไม่ได้อัปเดตในช่วงนั้น
วิธีแยกไบนารีปลอม ด้วย go version -m (อ่านไฟล์โดยไม่รัน):
- บรรทัด module เป็น pseudo-version
v0.15.1-0.20261013083505-5ead8ef9b43d+dirtyซึ่งเป็นสตริงที่ Go สร้างให้ build จาก commit ที่ไม่มีแท็ก ขณะที่รุ่นจริงแสดงเลขแท็ก - commit ที่บันทึกไว้เป็น
5ead8efไม่ใช่760fd72 - มีบรรทัด
-ldflags="-s -w"ขณะที่ไปป์ไลน์ของ OVHcloud ไม่แสดงบรรทัด-ldflagsเลย
ข้อควรระวังคือคำแนะนำที่แพร่ว่า build ใดมี +dirty หรือมีบรรทัด vcs คือตัวปลอมนั้นผิด เพราะ v0.16.0 รุ่นจริงก็แสดง v0.16.0+dirty และ vcs.modified=true เช่นกัน
ประเด็น GlassWorm: OpenSourceMalware โยงบัญชีนี้กับ GlassWorm แคมเปญมัลแวร์ที่ซ่อนโค้ดในอักขระ Unicode ที่มองไม่เห็นและดึงเพย์โหลดขั้นถัดไปจากช่อง memo ของธุรกรรมกระเป๋า Solana (ดูโพสต์ 2026/05/072) โดยพบว่า repository ส่วนตัว 4 แห่งของบัญชีนี้ถูก force-push เมื่อ 5-6 มีนาคม 2569 ด้วย commit ที่เพิ่ม loader ลักษณะนั้น และกระเป๋าที่ loader อ่านตรงกับแคมเปญ ForceMemo ของ GlassWorm แต่นักวิจัยยอมรับว่าการเชื่อมโยงว่าเป็นผู้โจมตีรายเดียวกันเป็น “การอนุมานของเรา” และยังไม่มีอะไรจากไบนารีเดือนตุลาคมที่ผูกกับ GlassWorm ได้ เพราะไม่มีใครเก็บสำเนาไว้
ผลกระทบ
เหยื่อที่น่าจะเป็นเป้าหมายคือวิศวกร DevOps และระบบ CI/CD ที่ใช้ OVHcloud CLI จัดการโครงสร้างพื้นฐานคลาวด์ ซึ่งมักเก็บข้อมูลรับรองสำคัญไว้บนเครื่อง ทั้ง API key ของ OVHcloud ในไฟล์ ~/.ovh.conf หรือตัวแปรสภาพแวดล้อม และความลับอื่นอย่าง SSH key, token ของ GitHub และข้อมูลรับรองคลาวด์รายอื่น ผู้ที่รันไบนารีปลอมจึงอาจเสียการควบคุมทรัพยากรคลาวด์ทั้งหมดที่เครื่องนั้นเข้าถึงได้ แม้หน้าต่างเวลาจะสั้นเพียง 94 นาที แต่ช่องทางติดตั้งหลักอย่างสคริปต์ curl | sh และคำสั่ง upgrade ในตัว ไม่ตรวจแฮชเลย
เหตุการณ์นี้ตอกย้ำว่าความปลอดภัยของซอฟต์แวร์ซัพพลายเชนไม่ได้จบที่ซอร์สโค้ดและไปป์ไลน์ build เพราะผู้โจมตีข้ามทั้งสองส่วนไปแก้ที่ไฟล์ release โดยตรง และการแก้ checksums.txt ไปพร้อมกันทำให้การตรวจแฮชจากไฟล์ใน release เดียวกันไร้ความหมาย สิ่งที่ช่วยได้จริงคือการตรึงแฮชไว้ฝั่งผู้ใช้ เช่นที่ Homebrew และ CI ของลูกค้ารายที่จับได้ทำ
คำแนะนำ
- ตรวจว่าเคยติดตั้งหรืออัปเดต OVHcloud CLI ในช่วง 12:47-14:21 UTC วันที่ 19 ตุลาคม 2569 (19:47-21:21 น. เวลาไทย) ผ่านช่องทางที่ได้รับผลกระทบหรือไม่ รวมถึงล็อกของงาน CI ช่วงนั้น
- ถ้ารันไบนารีปลอมหรือไม่แน่ใจ ให้ถือว่าความลับทุกอย่างที่อ่านได้จากเครื่องนั้นรั่วแล้ว และ หมุนเวียน (rotate) จากเครื่องอื่น ทั้ง OVHcloud API credential, SSH key, token และข้อมูลรับรองคลาวด์อื่น ก่อนติดตั้งใหม่
- ลบไบนารีเดิมแล้วติดตั้ง v0.16.0 ซึ่งเป็น immutable release พร้อม attestation และตรวจไฟล์ด้วย
gh release verify-asset v0.16.0 FILE - ห้ามรันไบนารีที่สงสัยเพื่อตรวจเวอร์ชัน ให้ใช้
go version -mอ่านข้อมูล build แทน - เลิกใช้รูปแบบติดตั้ง
curl | shใน CI และตรึงค่า SHA-256 ของไฟล์ที่ดาวน์โหลดไว้ใน pipeline เสมอ - ผู้ดูแลโครงการที่แจกจ่ายไบนารีผ่าน GitHub ควรเปิด release immutability บังคับ 2FA ให้ผู้มีสิทธิ์เขียน ทบทวนสิทธิ์ของ contributor ภายนอก และเปิดช่องทางรายงานช่องโหว่แบบส่วนตัว
Indicators of Compromise (IoCs)
| ประเภท | ค่า | คำอธิบาย |
|---|---|---|
| SHA-256 | 3833daffcaaaab27e4e0e0833240ffcb1df8df648f4ec0bc4a75c176e28933cb | archive Linux arm64 v0.15.0 ที่ถูกสลับ (ตัวเดียวที่เผยแพร่แฮช) |
| SHA-256 | 5c2beb56e6d83a4b426565a1557791ef759316abcc4effb38dd627c90aeb80e0 | archive Linux arm64 v0.15.0 ของจริง (ใช้เทียบ) |
| Go module version | v0.15.1-0.20261013083505-5ead8ef9b43d+dirty | pseudo-version ในไบนารีปลอม |
| Commit | 5ead8ef | commit ที่บันทึกในไบนารีปลอม (ของจริงคือ 760fd72) |
| Build flag | -ldflags="-s -w" | ปรากฏในไบนารีปลอม ไม่ปรากฏใน release จริง |
