การโจมตีช่องโหว่ CodeRabbit: จาก PR ธรรมดาสู่การได้ RCE และสิทธิ์เขียนบน 1 ล้านเรโป
(research.kudelskisecurity.com)- ทีมวิจัยด้านความปลอดภัยสามารถทำ remote code execution (RCE) บนเซิร์ฟเวอร์โปรดักชันของ CodeRabbit และ ทำให้ API token และข้อมูลลับรั่วไหล ได้สำเร็จ
- ด้วย PR ที่ใช้ Rubocop จึงสามารถขโมย environment variables และ เข้าถึง PostgreSQL รวมถึงอ่าน/เขียนเรโปสิทธิ์ได้ 1 ล้านรายการ
- จากการรั่วไหลของ private key ของ GitHub App ทำให้สามารถฉีดมัลแวร์ แก้ไขซอร์สโค้ด และสร้างความเสียหายจริงในคลังขนาดใหญ่ที่มีทั้ง public/private repo ได้
- ฝั่ง CodeRabbit ตอบสนองทันทีภายในไม่กี่ชั่วโมงหลังได้รับรายงานช่องโหว่ และเสริมมาตรการความปลอดภัยเพิ่มเติม
- มีการเน้นย้ำความจำเป็นของการ ป้องกันเหตุความปลอดภัย ด้วยการแยก sandbox จำกัดสิทธิ์ขั้นต่ำ และตัดการเชื่อมต่อเครือข่ายเมื่อรันเครื่องมือภายนอก
บทนำ
- ในเดือนมกราคม 2025 ทีมวิจัยของ Kudelski Security ได้เปิดเผยช่องโหว่ความปลอดภัยร้ายแรงของ CodeRabbit
- ใน CodeRabbit ซึ่งถูกใช้อย่างแพร่หลายเป็นเครื่องมืออัตโนมัติสำหรับรีวิว PR พบปัญหาสำคัญ ได้แก่ remote code execution (RCE), การรั่วไหลของ environment variables และข้อมูลอ่อนไหว, รวมถึงการได้สิทธิ์ Read/Write บนเรโปมากกว่า 1 ล้านรายการ
- บทความนี้เป็นการวิเคราะห์เชิงลึกของช่องโหว่ที่เปิดเผยในการนำเสนอที่ Black Hat USA และมีคุณค่าอย่างมากในฐานะ กรณีศึกษาจริงของช่องโหว่ในเครื่องมือรีวิวโค้ดและระบบที่เชื่อมต่อกัน
- ช่องโหว่ที่ถูกรายงานได้รับการแพตช์อย่างรวดเร็วทันทีหลังมีการแจ้ง
ภาพรวมของ CodeRabbit
- CodeRabbit เป็น แอปรีวิวโค้ดด้วย AI ที่มีการติดตั้งมากที่สุด ใน GitHub/GitLab Marketplace
- บนทั้งสองแพลตฟอร์มนี้มีการรีวิว 1 ล้านเรโปและ 5 ล้าน pull request
- ทุกครั้งที่ผู้ใช้สร้างหรืออัปเดต PR เอนจิน AI จะวิเคราะห์โค้ดและสร้างคอมเมนต์กับข้อเสนอแนะโดยอัตโนมัติ
- มีผลอย่างมากต่อการเพิ่ม ประสิทธิภาพการพัฒนา เช่น การสรุปโค้ด การตรวจหาช่องโหว่ความปลอดภัย การเสนอแนวทางปรับปรุง และการสร้างไดอะแกรม
การใช้งาน CodeRabbit และโครงสร้างสิทธิ์
- แผน Pro มีฟังก์ชันเชื่อมต่อกับเครื่องมือ linter และ SAST (การวิเคราะห์แบบสถิต)
- เมื่อยืนยันตัวตนด้วยบัญชี GitHub และติดตั้งแอป ผู้ใช้จะมอบ สิทธิ์อ่าน/เขียนแก่เรโปที่เลือก
- หากการจัดการสิทธิ์นี้ถูกนำไปใช้ในทางที่ผิด ก็อาจส่ง ผลกระทบโดยตรง ต่อโค้ดในทุกเรโปที่ติดตั้งไว้ได้
การรันเครื่องมือภายนอกและการค้นพบ exploit
- เมื่อ CodeRabbit ตรวจพบการเปลี่ยนแปลงของโค้ดใน PR ก็จะรัน เครื่องมือวิเคราะห์แบบสถิตภายนอกหลายตัวโดยอัตโนมัติ (เช่น Rubocop)
- Rubocop ถูกออกแบบให้ใช้ไฟล์ตั้งค่า
.rubocop.ymlเพื่อ โหลดไฟล์ Ruby ส่วนขยายภายนอก (เช่นext.rb) ได้- ผู้โจมตีสามารถแทรกโค้ดอันตรายลงใน
.rubocop.ymlและext.rbแล้วส่ง PR เพื่อชักนำให้ CodeRabbit รันโค้ดดังกล่าวบนเซิร์ฟเวอร์ระยะไกล
- ผู้โจมตีสามารถแทรกโค้ดอันตรายลงใน
- โค้ดที่ถูกรันด้วยเทคนิคนี้จะ ส่ง environment variables ทั้งหมดของเซิร์ฟเวอร์ไปยังเซิร์ฟเวอร์ของผู้โจมตี
การวิเคราะห์เนื้อหาที่รั่วไหลจาก environment variables
- ใน environment variables ที่รั่วไหล มี API key, token และรหัสผ่านของบริการหลากหลายประเภท รวมอยู่ด้วย เช่น
- Anthropic/OpenAI API key, encryption salt/password, private key ของ GitHub App, ข้อมูลการเชื่อมต่อ PostgreSQL เป็นต้น
- ผ่าน RCE จึงอาจเกิด ความเสียหายระลอกสองที่รุนแรงและขยายวงกว้าง เช่น การเข้าถึงฐานข้อมูล การแก้ไขโค้ด และการรั่วไหลของข้อมูลภายในบริการ
- แม้จะสามารถสำรวจเชิงรุกบนเซิร์ฟเวอร์จริงต่อได้มากกว่านี้ แต่ทีมวิจัยได้ตรวจสอบเพียงขั้นต่ำแล้วหยุด เพื่อคำนึงถึงการดำเนินงานของบริการ
การได้สิทธิ์ Read/Write บน 1 ล้านเรโป
- สามารถยืนยันตัวตนกับ GitHub API ได้โดยใช้
GITHUB_APP_PEM_FILE(private key) ที่อยู่ใน environment variables - ต่อทุกเรโปที่ CodeRabbit เข้าถึงได้ (รวมทั้ง public/private repository)
- สามารถใช้อำนาจสิทธิ์ที่รุนแรงมากได้ เช่น อ่าน/เขียนซอร์สโค้ด แทนที่ไฟล์รีลีส (โจมตีซัพพลายเชน) และแก้ไขประวัติ git
- มีการเผยแพร่ โค้ดสาธิตการทำซ้ำ (PoC) ซึ่งพิสูจน์แล้วว่าสามารถนำไปใช้โจมตีได้จริง
สรุป PoC
- ใช้ไลบรารีอย่าง PyGitHub พร้อม private key, App ID ที่รั่วไหล เพื่อ ออก access token สำหรับเข้าถึงเรโปใดก็ได้
- ด้วย token นี้สามารถทำงานอัตโนมัติได้ เช่น โคลน private repository, แก้ไขไฟล์, สร้าง commit ใหม่ และดัดแปลงไฟล์รีลีส
ความเป็นไปได้ในการเจาะเรโปภายใน/ไม่เปิดเผยของ CodeRabbit
- เนื่องจากองค์กร CodeRabbit เองก็ติดตั้งและใช้งานบริการของตนเองด้วย จึง สามารถเข้าถึงและโคลนเรโปซอร์สโค้ดภายในของ CodeRabbit ได้เช่นกัน
- หากรู้เพียงชื่อองค์กร ก็สามารถค้นหา installation ID แล้วเข้าถึงรายการเรโปนั้นได้ทันที
สรุปผลกระทบ
- การเข้าถึง private repository โดยไม่ได้รับอนุญาตและการรั่วไหลของข้อมูลส่วนบุคคล
- ภัยคุกคามของ การโจมตีซัพพลายเชน เช่น การดัดแปลงซอร์สโค้ด การฝังมัลแวร์/แบ็กดอร์
- ความเป็นไปได้ในการเชื่อมโยงกับช่องโหว่อื่นเพิ่มเติม เช่น GitHub Actions
- RCE โดยตรงอาจนำไปสู่การทำลายข้อมูล การทำให้บริการล่ม และความเสียหายลูกโซ่ต่อบริการอื่น
บริบทและข้อจำกัดของการตัดสินใจด้วย AI
- แม้ในระหว่างการโจมตี ตัว PR เองยังถูกรีวิวโดย CodeRabbit ตามปกติ และ แม้จะมีการทิ้งคอมเมนต์เตือนเรื่องช่องโหว่ แต่ก็ไม่สามารถระบุประโยคที่เป็นภัยคุกคามได้จริง
- สิ่งนี้แสดงให้เห็นว่า เครื่องมือรีวิวโค้ดด้วย AI ไม่ได้เข้าใจบริบทของสถานการณ์เสี่ยงจริงได้ครบถ้วน
การตอบสนองและข้อแนะนำ
- CodeRabbit ปิดการใช้งาน Rubocop, เปลี่ยนข้อมูลลับ และตรวจสอบระบบภายในไม่กี่ชั่วโมงหลังได้รับรายงานช่องโหว่
- ปัญหาเกิดจากเครื่องมือที่ไม่ได้ใช้ sandbox (Rubocop) และหลังจากนั้นได้ปรับปรุงให้ รันเครื่องมือภายนอกทั้งหมดในสภาพแวดล้อมที่แยกออกจากกัน
- เพื่อเสริมความปลอดภัย มีการเน้นย้ำถึงความจำเป็นของ การออกแบบเชิงป้องกัน เช่น ลด environment variables ให้เหลือน้อยที่สุด จำกัด IP ที่เข้าถึงเครือข่ายได้ และปิดกั้นการเข้าถึงอินเทอร์เน็ตในสภาพแวดล้อมที่รันเครื่องมือภายนอก
การเปิดเผยอย่างมีความรับผิดชอบและบทสรุป
- ในเดือนมกราคม 2025 หลังการแจ้ง มีการตอบสนองและดำเนินมาตรการอย่างรวดเร็ว
- แม้จะหยุดไว้ที่ PoC แต่ก็ยืนยันได้ว่าหากเป็นผู้โจมตีจริง ก็สามารถนำไปใช้ในทางที่ผิดได้ง่าย เช่น คัดเลือกเรโปมูลค่าสูง ปล่อย ransomware ในวงกว้าง หรือโจมตีซัพพลายเชนแบบทำลายล้าง
- เรื่องนี้ย้ำอีกครั้งถึงความสำคัญของการใช้ sandbox และหลักสิทธิ์ขั้นต่ำ เมื่อเชื่อมต่อกับ เครื่องมือวิเคราะห์ภายนอกและบริการอัตโนมัติที่ขับเคลื่อนด้วย AI
1 ความคิดเห็น
ความเห็นจาก Hacker News
โอ้โห นี่เป็นช่องโหว่ที่ร้ายแรงมาก โชคดีที่แก้ไขแล้ว แต่การที่มีปัญหาแบบนี้ตั้งแต่แรกก็น่าเป็นห่วง กฎพื้นฐานที่สุดของการสร้างระบบที่วิเคราะห์โค้ดผู้ใช้บนแพลตฟอร์มคลาวด์คือ ตัววิเคราะห์ต้องรันในสภาพแวดล้อมที่แยกออกจากกันเสมอ เพราะสามารถเกิดการฉีดโค้ดได้โดยตรงผ่านปลั๊กอิน และ linter/ตัววิเคราะห์/compiler ก็เป็นซอฟต์แวร์ซับซ้อนที่มีพื้นที่ผิวของช่องโหว่กว้างมาก ไม่ควรตั้งสมมติฐานเด็ดขาดว่าการรันเครื่องมือพวกนี้กับรีโพใดๆ ในสภาพแวดล้อมที่ใช้ร่วมกันจะปลอดภัย ผมเองก็เคยดูแลแพลตฟอร์มวิเคราะห์โค้ด และแม้แต่ตอนรันตัววิเคราะห์ที่เราพัฒนาเองกับรีโพของลูกค้า ก็ยังออกแบบให้ทำงานใน sandbox โดยไม่ให้สิทธิ์ตัวแปรสภาพแวดล้อมหรือการเรียกเครือข่าย การวิเคราะห์ต้องรันใน sandbox เท่านั้น นี่คือวิธีเดียวที่จะทำให้การวิเคราะห์โค้ดปลอดภัย
https://github.com/getgrit/gritql
ยกเลิกการสมัครแบบเสียเงินของ Coderabbit แล้ว สิ่งที่น่ากังวลเสมอคือบริษัทต้องรอให้เรื่องไวรัลบน HN ก่อนถึงจะยอมรับปัญหา ในบล็อกทางการก็ไม่มีที่ไหนพูดถึงช่องโหว่นี้เลย และวันนี้ก็ไม่มีโพสต์ใหม่ ผมคิดว่าใครๆ ก็พลาดกันได้ แต่การไม่เปิดเผยอย่างโปร่งใสเมื่อเกิดเรื่องแบบนี้ทำลายภาพลักษณ์ของบริษัท
ประโยคที่ว่า "ระหว่างที่ exploit ทำงาน CodeRabbit กลับทิ้งคอมเมนต์เตือนอันตรายใน PR เอง ทั้งที่สถานการณ์จริงคือมันกำลังโดนแฮ็กจากการรัน PR นั้น" มันประหลาดมาก รู้สึกแปลกแยกกับโลกที่ AI กำลังบอกว่าตัวเองโดนแฮ็กอยู่ และแม้ทีม CodeRabbit จะตอบสนองได้รวดเร็ว แต่สิ่งที่น่ากังวลกว่าคือ "ผู้ให้บริการรายอื่นไม่ตอบแม้แต่การติดต่อให้ตรวจสอบ และยังคงมีช่องโหว่อยู่" ต้องปรบมือให้ทีม CodeRabbit แต่ทุกคนก็ควรเดินเกมอย่างระมัดระวัง
ในแถลงการณ์อย่างเป็นทางการของ CEO มีช่วงหนึ่งบอกว่า "ปัญหาเกิดจาก Rubocop รันอยู่นอก sandbox" แต่พูดตรงๆ ว่าฟังดูน่าสงสัย ทำไมมีแค่งานเดียวที่ทำงานต่างจากตัวอื่นแบบสิ้นเชิง และดันเป็นงานที่โดนเจาะพอดี?
เป็นบทความที่น่าสนใจมาก แต่จริงๆ ก็ไม่ได้เหนือความคาดหมาย ผู้ใช้เพิ่มแอปที่สิทธิ์กว้างเกินไปโดยไม่คิดมากกันเยอะมาก และระบบสิทธิ์ของ github เองก็มีปัญหา เรื่องแบบนี้เลยแทบหลีกเลี่ยงไม่ได้ หลายคนยอมให้ github app มีสิทธิ์เขียนรีโพ รวมถึงสิทธิ์บนคลาวด์อย่างฟุ่มเฟือย แม้จะมี branch protection ก็ยังเข้าถึงสิทธิ์พิเศษผ่าน github actions จาก pull request ได้ ถ้าจะตั้งค่าให้ถูกต้องต้องแก้ github oidc audience ซึ่งเอกสารก็เขียนไว้ไม่ดีนัก ต่อให้ขอให้ผู้พัฒนาแอปทำเวอร์ชันแยกที่ลดสิทธิ์ลงและปิดบางฟีเจอร์ ส่วนใหญ่ก็ไม่สนใจและไม่เข้าใจปัญหาด้านความปลอดภัย github ควรเปิดให้กำหนดสิทธิ์การเข้าถึงของแอปได้ละเอียดกว่านี้ และภาพรวมของสิทธิ์ทั้งหมดก็ควรละเอียดขึ้นด้วย
ช็อกมาก ยังอ่านไม่จบด้วยซ้ำ แต่ข้อมูลเยอะจนมึนไปหมด ตอนที่บอกว่าแฮ็กเกอร์อาจฝังมัลแวร์ลงในไฟล์แจกจ่ายของเครื่องมือ/ไลบรารี/ซอฟต์แวร์โอเพนซอร์สระดับ 100,000 ถึง 1,000,000 รายการได้ ทำให้รู้สึกเหมือนโลกอาจล่มสลายได้เลย ยากจะจินตนาการว่ายังมีปัญหาแบบเดียวกันอีกมากแค่ไหนในอนาคต
ผมคิดว่าความล้มเหลวด้านความปลอดภัยร้ายแรงแบบนี้ควรถูกจัดเป็น "การละเมิด" หรือ "เหตุการณ์" และต้องเปิดเผยต่อสาธารณะผ่านสื่ออย่างเป็นข้อบังคับ เครื่องมือที่เข้าถึงลูกค้าราว 7,000 รายและรีโพ 1 ล้านรายการ กลับถูกเจาะด้วย exploit ง่ายๆ ที่เด็กอายุ 11 ขวบก็อาจทำได้ ถ้ามันแฮ็กง่ายขนาดนี้ ก็มีความเป็นไปได้สูงว่า bot, blackhat, APT ต่างๆ อาจเจาะเข้าไปและฝังตัวเงียบๆ ไว้แล้วก่อนหน้านี้ ถ้า whitehat มาเปิดเผยทีหลัง การแพตช์ช่องโหว่ก็แค่กันผู้โจมตีรายใหม่ แต่ไม่แน่ว่าจะกำจัดผู้ที่แอบอยู่ข้างในได้ เข้าใจว่าความปลอดภัยเป็นเรื่องยาก แต่ก็อยากบอกว่าต้องตั้งสติกันจริงๆ
ปัญหาอย่างหนึ่งคือ code analyzer, bundler, compiler ต่างๆ (เช่น Rust compiler) สามารถรันโค้ดตามอำเภอใจได้โดยไม่เตือนอะไรเลย ตัวอย่างเช่น แฮ็กเกอร์ส่งรีโพหนึ่งมาให้โดยอ้างว่าเป็นแบบทดสอบสมัครงาน แล้วถ้าผมรัน “npm install” หรือคำสั่งคอมไพล์ Rust เครื่องผมก็อาจตกอยู่ในมือแฮ็กเกอร์ทันที หรือถ้าคอมของเพื่อนร่วมงานคนหนึ่งโดนเจาะแล้วมัลแวร์ถูกใส่เข้าไปในรีโพ สุดท้ายทั้งบริษัทยักษ์ใหญ่ระดับโลกก็อาจถูกแฮ็กเกอร์จากต่างชาติยึดได้ โครงสร้างแบบนี้เกิดจาก npm และ Rust compiler เอง เครื่องมือแบบนี้ควรขอการยืนยันอย่างชัดเจนทุกครั้งที่จะรันคำสั่งภายนอก (อาจแคช allowlist ของคำสั่งไว้เพื่อไม่ต้องถามซ้ำได้) ฝั่ง Linux เองก็ควรมี sandbox ที่ปลอดภัยและใช้ง่ายสำหรับนักพัฒนา ตอนนี้กลับต้องมานั่งทำเองทั้งหมด นอกจากนี้ยังมีงานบางอย่างอย่างการติดตั้งแพ็กเกจ JS ที่จริงๆ แล้วไม่จำเป็นต้องรันโค้ดภายนอกเลย และการเอาความลับกับค่าคอนฟิกไปใส่ไว้ใน environment variable ก็เป็นวิธีที่แย่มาก คนที่คิด "12-factor app" ขึ้นมาดูเหมือนไม่รู้ว่ามี command-line switch หรือไฟล์คอนฟิกอยู่ด้วย
psก็เห็นข้อมูลทั้งหมดแล้วการเก็บกุญแจสิทธิ์ (private key) ที่สามารถทำตัวเป็น github app ได้ตามต้องการไว้ใน environment variable เป็นแนวปฏิบัติที่แย่มาก ใครๆ ก็โดนแฮ็กได้ก็จริง แต่นี่คือพื้นฐานที่สุดของการจัดการความลับ เอกสารทางการของ github ก็เขียนชัดเจนว่าไม่ควรใส่ private key ลงใน environment variable นี่เป็นเรื่องพื้นฐานมากจริงๆ
https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps#storing-private-keys
ทันทีที่อ่านประโยคว่าคอนฟิกของ Rubocop สามารถระบุพาธไฟล์ Ruby แบบขยายได้ ก็คิดเลยว่า "อย่าบอกนะว่าเอาเครื่องมือ extension ของผู้ใช้ไปรันตรงบน production..." แล้วก็ใช่จริงๆ แน่นอนว่าแค่ปิดรูนี้รูเดียวไม่ได้แปลว่าปลอดภัยอย่างถูกต้อง linter ส่วนใหญ่ก็คงแทบไม่เคยผ่านการ audit หรือ fuzzing สำหรับอินพุตเชิงโจมตีด้วยซ้ำ นี่เหมือนเปิดประตูทิ้งไว้แล้วติดป้ายนีออนว่า “เชิญมาแฮ็กได้เลย!”