InvoiceShelf ได้ออกแพตช์สำหรับ CVE-2026-55610 ซึ่งเป็นช่องโหว่ร้ายแรงที่ช่วยให้ Owner ในบริษัทหนึ่งสามารถเข้ายึดบัญชีผู้ใช้ในอีกบริษัทหนึ่งได้ ช่องโหว่นี้ได้รับคะแนน 8.7 บนมาตรวัด CVSS ซึ่งเกิดจากการขาดการตรวจสอบขอบเขตของเทแนนท์ (tenant-scope check) ในโค้ด Laravel ของแอปพลิเคชัน

กลไกการทำงานของช่องโหว่

InvoiceShelf เป็นเครื่องมือ SaaS ที่สร้างขึ้นบน Laravel ซึ่งช่วยให้บริษัทต่างๆ สามารถจัดการผู้ใช้ ใบแจ้งหนี้ และการตั้งค่าต่างๆ ได้จากแดชบอร์ดเดียว แพลตฟอร์มนี้จะอ่าน custom header เพื่อระบุตัวตนของเทแนนท์ (tenant) เมื่อ Owner ร้องขอข้อมูลผู้ใช้ โค้ดจะตรวจสอบเพียงแค่ว่า “ผู้ร้องขอเป็น Owner ของบริษัทตนเองใช่หรือไม่?” เท่านั้น

แต่มันไม่เคยตรวจสอบเลยว่าผู้ใช้เป้าหมายนั้นอยู่ในเทแนนท์เดียวกันหรือไม่ การทำ implicit route-model binding ของ Laravel จะทำการจับคู่ user ID กับแถวข้อมูลในตาราง users ส่วนกลาง (global users table) และนโยบายการอนุญาตสิทธิ์ (authorization policy) จะอนุมัติคำร้องขอโดยพิจารณาจากบทบาท (role) ของผู้ร้องขอเพียงอย่างเดียว

ดังนั้น ผู้โจมตีจึงสามารถ:

  • ส่ง numeric user ID ใดๆ ผ่าน URL ของคำร้องขอ
  • ได้รับข้อมูลผู้ใช้ฉบับเต็ม รวมถึงอีเมล
  • ส่งคำสั่งอัปเดตเพื่อเขียนทับอีเมล รหัสผ่าน และแม้กระทั่งเปลี่ยนการมอบหมายบัญชีให้ไปเป็นของบริษัทผู้โจมตีในฐานะ super-admin

ในทางปฏิบัติ Owner ที่ประสงค์ร้ายได้เปลี่ยนเครื่องมือจัดการบริษัทให้กลายเป็นอาวุธในการยึดบัญชีแบบครอบจักรวาล โดยไม่จำเป็นต้องมีสิทธิ์ใดๆ นอกเหนือจาก “Owner” เลย

ใครที่ได้รับผลกระทบ

ลูกค้า InvoiceShelf ทุกรายที่ใช้เวอร์ชันก่อน 2.4.1 ตกอยู่ในความเสี่ยง เนื่องจากช่องโหว่นี้อยู่ในเส้นทางการจัดการคำร้องขอหลัก (core request-handling path) ทำให้เทแนนท์ใดๆ ก็ตามอาจตกเป็นเป้าหมายของ Owner จากเทแนนท์อื่นได้ โดยไม่คำนึงถึงขนาดหรือมาตรการความปลอดภัย ผลกระทบที่เกิดขึ้นรวมถึงการสูญเสียความลับของข้อมูล (ที่อยู่อีเมล) และการสูญเสียความถูกต้องครบถ้วนของข้อมูล (การเปลี่ยนรหัสผ่านโดยไม่ได้รับอนุญาต และการยกระดับสิทธิ์เป็น super-admin)

แพตช์แก้ไข

นักพัฒนาได้ออกเวอร์ชัน 2.4.1 โดยเพิ่มการตรวจสอบเทแนนท์อย่างชัดเจน (explicit tenant check) ก่อนการดำเนินการอ่านหรือเขียนข้อมูลใดๆ ในบันทึกของผู้ใช้ การแก้ไขนี้จะจำกัดขอบเขตของคิวรี (query) ไปยังตัวระบุบริษัทที่ใช้งานอยู่ (active company identifier) ซึ่งบังคับให้ Laravel คืนค่าเฉพาะแถวข้อมูลที่เป็นของเทแนนท์ของผู้ร้องขอเท่านั้น

สิ่งที่นักพัฒนาควรเรียนรู้

  • อย่าพึ่งพา global primary keys ในแอปพลิเคชันแบบ multi-tenant
  • ใช้ tenant filter ในการค้นหาฐานข้อมูลทุกครั้ง ไม่ใช่แค่เฉพาะการลบหรือการสร้างข้อมูลเท่านั้น
  • กำหนดให้นโยบายการอนุญาตสิทธิ์ (authorization policies) ตรวจสอบทั้งบทบาทของผู้กระทำ และ ความเป็นเจ้าของเทแนนท์ (tenancy) ของวัตถุเป้าหมาย
  • มองว่าฟีเจอร์อัตโนมัติของเฟรมเวิร์ก เช่น route-model binding เป็นเพียงความสะดวกสบายที่อาจซ่อนช่องโหว่ด้านความปลอดภัยได้ เว้นแต่คุณจะเพิ่มการกำหนดขอบเขต (scoping) อย่างชัดเจน

มองไปข้างหน้า

เหตุการณ์นี้แสดงให้เห็นถึงความเสี่ยงที่กว้างขึ้นสำหรับ SaaS ใดๆ ที่มีการใช้ตารางข้อมูลร่วมกัน การตรวจสอบความปลอดภัย (security audits) ควรทบทวนทุก endpoint ที่รับค่า identifiers และยืนยันว่ามีการบังคับใช้การกำหนดขอบเขตเทแนนท์ (tenant scoping) อย่างสม่ำเสมอทั่วทั้งระบบ

บทสรุป: การขาดการตรวจสอบเทแนนท์เพียงจุดเดียวสามารถเปลี่ยนบทบาทผู้ใช้ที่มีสิทธิ์ให้กลายเป็นช่องโหว่ (backdoor) แบบครอบจักรวาลได้ การกำหนดขอบเขต (scoping) ที่เหมาะสมไม่ใช่ทางเลือก แต่เป็นรากฐานของการแยกข้อมูล (data isolation) ในระบบ multi-tenant ทุกระบบ