DeepSeek Harness ปล่อยให้ผู้โจมตีใน sandbox สามารถรันคำสั่งใดๆ ก็ได้ เพียงแค่เปลี่ยน HTTP Host header เป็น 127.0.0.1 ซึ่งมีคะแนนสูงถึง 9.4 บนมาตรวัด CVSS ข้อบกพร่องนี้แสดงให้เห็นว่าการตัดสินใจเชื่อถือข้อมูลผิดที่เพียงจุดเดียว สามารถเปลี่ยนขอบเขตการป้องกันให้กลายเป็นประตูหลัง (backdoor) ที่เปิดกว้างได้
How the bug slipped in
ช่องโหว่นี้อยู่ในฟังก์ชันเดียวที่อ่าน Host header ของคำขอ และหากค่าดังกล่าวเท่ากับ loopback address ระบบจะปฏิบัติกับคำขอนั้นเสมือนว่ามาจากเครื่องในเครื่อง (local machine)
ผู้โจมตีที่สามารถรันโค้ดภายใน sandbox ได้ไม่จำเป็นต้องใช้ payload ที่ซับซ้อน เพียงแค่ส่ง HTTP request หนึ่งรายการที่มี Host: 127.0.0.1 ระบบ backend ก็จะเชื่อว่าการเรียกใช้งานนั้นมาจากตัว host เอง และจะข้ามขั้นตอนการแจ้งเตือนความปลอดภัย การตรวจสอบ rate-limit และขั้นตอนการตรวจสอบความถูกต้องของคำสั่งทั้งหมด ผลลัพธ์ที่ได้คือ: การรันคำสั่งได้อย่างไม่จำกัดโดยไม่ต้องมีการโต้ตอบเพิ่มเติมใดๆ
Why trusting headers is dangerous
Header คือสตริงข้อความธรรมดาที่ส่งมาจากผู้เรียกใช้งาน ไม่ว่าฟิลด์นั้นจะชื่อ Host, X-Forwarded-For หรือชื่อที่กำหนดเองก็ตาม ฝั่ง client สามารถตั้งค่าเป็นค่าใดก็ได้ตามต้องการ แหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียวเกี่ยวกับที่มาที่แท้จริงของการเชื่อมต่อคือ transport layer หรือที่อยู่ IP ต้นทางของ socket ที่ระบบปฏิบัติการบันทึกไว้เมื่อการทำ TCP handshake เสร็จสมบูรณ์
เมื่อแอปพลิเคชันตัดสินใจเชื่อถือ header โดยไม่ยืนยันว่ามีการฉีด (inject) ข้อมูลนั้นมาจาก proxy ที่รู้จักและกำหนดค่าไว้อย่างถูกต้อง ก็เท่ากับเป็นการมอบกุญแจสำคัญในการควบคุมระบบทั้งหมดให้แก่ผู้โจมตี ช่องโหว่ของ DeepSeek Harness คือตัวอย่างที่ชัดเจนของความผิดพลาดนี้
Real-world impact: the shell.online example
โปรเจกต์โอเพนซอร์ส shell.online ซึ่งให้บริการเทอร์มินัลผ่านเว็บ ได้บันทึกข้อผิดพลาดแบบเดียวกันนี้ไว้เมื่อเร็วๆ นี้ โดยมีการใช้แฟล็กการกำหนดค่าที่เรียกว่า TRUST_PROXY:
- TRUST_PROXY = 0 – แอปพลิเคชันจะเพิกเฉยต่อ header X-Forwarded-For และอาศัยที่อยู่ remote address ของ socket แทน วิธีนี้จะช่วยป้องกันไม่ให้ client ปลอมแปลง IP address เพื่อหลบเลี่ยง rate limits หรือปลอมตัวเป็นผู้ใช้ที่ได้รับความไว้วางใจ
- TRUST_PROXY = 1 – แอปพลิเคชันจะเชื่อถือ header X-Forwarded-For ว่าเป็นตัวตนของ client หากบริการนั้นไม่ได้อยู่หลัง proxy จริงๆ ที่ทำหน้าที่ล้างข้อมูล (sanitise) header นี้ ผู้โจมตีจะสามารถส่ง IP address ใหม่ในทุกๆ คำขอ ซึ่งส่งผลให้สามารถรีเซ็ตการจำกัดความเร็ว (throttling) ต่อหนึ่ง IP ได้อย่างมีประสิทธิภาพ
ช่องโหว่ของ DeepSeek สะท้อนถึงสถานการณ์นี้: โค้ดเชื่อถือ Host ราวกับว่ามี proxy เป็นผู้กำหนดค่าให้ ทั้งที่บริการดังกล่าวสามารถเข้าถึงได้โดยตรง
What developers need to do now
- ตรวจสอบทุกจุดที่คุณอ่าน header ที่ส่งมาจาก client ระบุว่า header ใดที่คุณถือว่าเป็นข้อมูลอ้างอิงที่เชื่อถือได้ (เช่น Host, X-Forwarded-For, X-Real-IP) และตรวจสอบให้แน่ใจว่ามี proxy ที่เชื่อถือได้ทำการเขียนทับ (rewrite) ข้อมูลเหล่านั้นก่อนจะถึงแอปพลิเคชันของคุณ
- ผูกการตัดสินใจด้านความปลอดภัยเข้ากับ socket address เมื่อเป็นไปได้ ให้ใช้ IP ต้นทางที่ระบบปฏิบัติการจัดหาให้สำหรับการตรวจสอบสิทธิ์ (authentication), การจำกัดอัตราการใช้งาน (rate-limiting) และการตรวจสอบการควบคุมการเข้าถึง (access-control)
- เปิดใช้งานแฟล็ก proxy-trust เฉพาะเมื่อมี reverse proxy ที่กำหนดค่าอย่างถูกต้องวางอยู่หน้าบริการเท่านั้น หากคุณรันแอปพลิเคชันโดยตรง ให้ปิดแฟล็กเหล่านั้นไว้
- จัดทำเอกสารโครงสร้างการติดตั้งระบบ (deployment topology) ที่จำเป็น ไว้ใน README หรือคู่มือการติดตั้งของโปรเจกต์ เพื่อให้ผู้ใช้ที่ติดตั้งระบบด้วยตนเอง (self-host) ทราบถึงข้อกำหนดเรื่อง proxy-trust
- ใช้เครื่องมือ static-analysis หรือเครื่องมือตรวจสอบโค้ด (code-review tools) ที่จะแจ้งเตือนเมื่อมีการใช้ header โดยตรงเพื่อการตัดสินใจด้านความปลอดภัย โดยไม่มีตรรกะการตรวจสอบ proxy ควบคู่ไปด้วย
What to watch next
ชุมชนที่ให้บริการเว็บเซอร์วิสแบบ self-hosted มีแนวโน้มที่จะกลับไปตรวจสอบการตั้งค่า proxy-trust ของตนเองอีกครั้งหลังจากเหตุการณ์นี้
บทเรียนสำคัญนั้นชัดเจน: อย่าปล่อยให้ข้อความเพียงชุดเดียวที่ใครก็ได้บนอินเทอร์เน็ตสามารถเขียนขึ้นมา เป็นตัวกำหนดระดับความปลอดภัยของระบบของคุณ จงเชื่อถือเลเยอร์เครือข่าย (network layer) ไม่ใช่เลเยอร์ของคำขอ (request layer)
