สรุปสั้น

อีเมลส่วนตัวที่ GitLab มอบให้ผู้ใช้แต่ละคนเพื่อเปิด issue ทางอีเมลนั้น แท้จริงแล้วทำหน้าที่เป็นข้อมูลรับรอง (credential) โดยใครก็ตามที่ได้อีเมลนี้ไปสามารถส่งแพตช์ให้ GitLab commit ในชื่อเจ้าของบัญชี ไปยัง branch ใดก็ได้ที่เจ้าของ push ได้ รวมถึง main และสามารถสั่งรันงาน CI/CD ที่ทำงานในชื่อเจ้าของได้ด้วย GitLab แสดงอีเมลนี้ให้ผู้ใช้แต่ละคนหลังปุ่ม “Email work item to this project” โดยข้อความที่ส่งไปยังที่อยู่นี้จะเปิด issue ในโปรเจกต์นั้น พร้อมระบุว่าเจ้าของบัญชีเป็นผู้เขียน

จุดสำคัญคือสตริงตรงกลางอีเมลเป็นโทเคนที่ผูกกับบัญชี และเอกสารของ GitLab ระบุว่าโทเคนนี้ไม่หมดอายุ บริษัท Aikido Security ที่รายงานพฤติกรรมนี้พบว่าอีเมลที่ GitLab สร้างให้โปรเจกต์ต่าง ๆ ของผู้ใช้คนเดียวกันใช้โทเคนเดียวกันทั้งหมด และโทเคนนั้นใช้ได้กับทุกโปรเจกต์ที่บัญชีเข้าถึงได้ ไม่ว่าจะเป็นโปรเจกต์สาธารณะหรือส่วนตัว ที่แย่กว่านั้นคือ GitLab ไม่ตรวจสอบว่าใครเป็นผู้ส่งอีเมล กล่องเมลใด ๆ ก็เขียนไปยังที่อยู่นี้ได้ และ GitLab จะดำเนินการราวกับว่าข้อความมาจากเจ้าของบัญชี

รายละเอียดข่าว

เว็บไซต์ The Hacker News รายงานเมื่อวันที่ 23 กันยายน 2569 ว่า อีเมลสำหรับเปิด issue ของ GitLab ทำหน้าที่เป็น credential ที่ทรงพลังกว่าที่ผู้ใช้ส่วนใหญ่เข้าใจ

บริษัท Aikido Security แสดงให้เห็นว่าผู้ที่ถืออีเมลนี้สามารถเปลี่ยนจากการเปิด issue ไปเป็นการ commit โค้ดได้ โดยอาศัยฟีเจอร์ merge request ทางอีเมลของ GitLab เอง เพียงเปลี่ยนส่วนท้ายของอีเมลจาก -issue เป็น -merge-request GitLab ก็จะเปิด merge request แทน issue จากนั้นเขียนแพตช์ ใส่ชื่อ branch เป้าหมายในหัวเรื่องอีเมล แนบแพตช์แล้วส่ง GitLab จะนำแพตช์ไปใช้กับ branch นั้นและสร้าง branch หากยังไม่มี การเปลี่ยนแปลงจะกลายเป็น commit บน branch ที่ระบุ โดยมีเจ้าของบัญชีเป็นผู้เขียน ถ้าเป็น branch ที่เจ้าของ push ได้ ก็รวมถึง main และหากแพตช์แก้ไฟล์ .gitlab-ci.yml ของโปรเจกต์และบทบาทของเจ้าของอนุญาต GitLab ก็จะรันงานของผู้โจมตีในชื่อเจ้าของ

มีสองปัจจัยที่ช่วยจำกัดความเสียหาย ปัจจัยแรกคือโทเคนถือเพียงสิทธิ์ของเจ้าของบัญชี ระดับที่ผู้โจมตีไปถึงได้จึงขึ้นกับบทบาทของเจ้าของ อีเมลของบัญชี Guest แทบไร้ประโยชน์ ขณะที่ของบัญชี Maintainer เข้าถึง branch ที่ป้องกันไว้และความลับ CI/CD ได้ ปัจจัยที่สองคือการเข้าถึงโปรเจกต์ต้องใช้มากกว่าแค่อีเมล เพราะ GitLab หาเป้าหมายจาก path และหมายเลข ID ของโปรเจกต์ ผู้โจมตีที่ต้องการเจาะโปรเจกต์เฉพาะจึงต้องรู้ทั้ง path และ ID ควบคู่กับโทเคน โปรเจกต์สาธารณะเปิดเผยทั้งสองอย่าง ส่วนโปรเจกต์ส่วนตัวต้องอาศัยการรั่วไหลแยกต่างหากที่ระบุชื่อ แม้ ID ของ GitLab จะเดาได้ไม่ยาก

Leaked GitLab issue email address lets anyone push code and run CI jobs as you

วิธีการโจมตี

เนื่องจากอีเมลขาเข้าได้รับการยกเว้นจากการจำกัด IP การโจมตีจึงเริ่มจากภายนอก IP allowlist ได้ Aikido ทดสอบด้วยการล็อกโปรเจกต์ส่วนตัวไว้กับ IP เดียวที่ไม่ใช่ของตัวเอง GitLab บล็อกเบราว์เซอร์และปฏิเสธ git clone แต่กลับยอมรับอีเมล merge request และ commit ก็ลงบน main สำเร็จ เส้นทางเดียวกันนี้ยังข้ามการยืนยันตัวตนสองปัจจัย (2FA) ด้วย โดยเอกสารของ GitLab ระบุว่าฟีเจอร์อีเมลขาเข้าทำงานได้โดยไม่ต้อง 2FA แม้ในระบบที่บังคับใช้

ทุกบัญชีบน GitLab.com มีโทเคนแบบนี้หนึ่งตัว และ GitLab แบบ self-managed ทุกระบบที่เปิดอีเมลขาเข้า (ซึ่งเป็นค่าเริ่มต้นบน GitLab.com) ก็มีเช่นกัน ส่วน GitLab Dedicated ดูเหมือนจะไม่ได้รับผลกระทบ เพราะ GitLab จำกัดฟีเจอร์นี้ไว้กับ self-managed และ GitLab.com แม้ Aikido จะระบุว่าทดสอบ Dedicated โดยตรงไม่ได้ ทั้งนี้ GitLab ปรับข้อความรอบโทเคนหลัง Aikido รายงาน โดยระบุว่าอีเมลสร้างได้ทั้ง issue และ merge request และลบบรรทัดที่เคยบอกว่าโทเคนใช้เข้าถึงข้อมูลอื่นไม่ได้ออก แต่พฤติกรรมไม่ได้เปลี่ยน โทเคนยังไม่หมดอายุ GitLab ยังไม่ตรวจว่าใครส่งอีเมล และยังไม่มีสวิตช์ให้ผู้ใช้รายบุคคลปิดฟีเจอร์นี้

ผลกระทบ

ช่องทางนี้อันตรายเพราะเปลี่ยนสิ่งที่ผู้ใช้มองว่าเป็นเพียงอีเมลแจ้งบั๊ก ให้กลายเป็นกุญแจที่ commit โค้ดในชื่อเจ้าของและรัน CI/CD ได้ โดยข้ามทั้ง IP allowlist และ 2FA ที่องค์กรตั้งไว้ ยิ่งเจ้าของบัญชีมีบทบาทสูง เช่น Maintainer ความเสียหายยิ่งใหญ่ เพราะเข้าถึง branch ที่ป้องกันและความลับ CI/CD ได้ ที่น่ากังวลคือ Aikido พบอีเมลที่ยังใช้งานได้ราวหนึ่งโหลจากการค้นหา ส่วนใหญ่ถูกเผยแพร่โดยตั้งใจเป็นที่อยู่รับรายงานบั๊ก และบางส่วนอยู่ในโปรเจกต์โอเพนซอร์สที่ใช้กันแพร่หลาย การรั่วของอีเมลเพียงที่อยู่เดียวจึงอาจเปิดทางฝังโค้ดร้ายในซอฟต์แวร์ที่มีผู้ใช้จำนวนมากในลักษณะ supply chain

คำแนะนำ

ผู้ใช้ไม่สามารถห้ามคนอื่นมีฟีเจอร์นี้ได้ แต่ตัดอีเมลที่รั่วไปแล้วได้ด้วยการรีเซ็ตโทเคน incoming email จากหน้า personal access tokens ในโปรไฟล์ ซึ่งจะเปลี่ยนอีเมลของทุกโปรเจกต์พร้อมกัน (อีเมลที่ใช้อยู่จะหยุดทำงานจนกว่าจะแจกที่อยู่ใหม่) จากนั้นควรตรวจ README, คู่มือการมีส่วนร่วม และหน้าสนับสนุนของตัวเองว่ามีการโพสต์อีเมลนี้ไว้หรือไม่ สำหรับระบบ self-managed ผู้ดูแลสามารถปิดอีเมลขาเข้าทั้งระบบได้ แต่ไม่มีการตั้งค่าที่ให้ผู้ใช้รายบุคคลปิดการสร้าง issue หรือ merge request ทางอีเมลเฉพาะบัญชีตัวเอง

แหล่งอ้างอิง