CVE-2025–29927: Authorization Bypass via Middleware in Next.js

สวัสดีเพื่อน ๆ นักอ่านทุกท่านที่ได้หลงทางเข้ามาอ่านบทความนี้กันนะครับ ซึ่งในบทความนี้ผมจะมาพูดถึงช่องโหว่ของ CVE-2025–29927 กัน โดยช่องโหว่ตัวนี้จะเป็นช่องโหว่ของเฟรมเวิร์ก Next.js ที่มีการใช้งานตัวของ Middleware เป็นตัวกลางในการจัดการกับ Request ต่าง ๆ ที่เข้ามา เปรียบเสมือนเป็นด่านที่เอาไว้คอยตรวจสอบ Request ต่าง ๆ นั้นเอง
Middleware คืออะไร?
Middleware เป็นหนึ่งในฟีเจอร์ของ Next.js ที่ใช้รวมกับแอปพลิเคชันเพื่อยกระดับความปลอดภัยของตัวแอปให้มากขึ้น โดยมันจะมีหน้าที่เป็นตัวกลางระหว่าง User กับแอปพลิเคชัน ซึ่งจะใช้สำหรับจัดการ Request ต่าง ๆ ที่เข้ามาจาก User ไม่ว่าจะเป็นตรวจสอบการยืนยันตัวตน, ตรวจสอบสิทธิ์, ตรวจจับ Request ที่เป็น bot, เก็บข้อมูลและวิเคราะห์ Request จาก User ที่เข้ามาใช้งาน หรือเปลี่ยนเส้นทาง (Redirect) ของ Request ให้ไปอีกที่หนึ่งที่ต้องการได้ โดยบริบทการใช้งานของตัว Middleware จะขึ้นอยู่กับเจ้าของแอปพลิเคชันเป็นหลักว่าอยากให้ทำอะไรบ้าง
ซึ่งบางครั้งตัว Middleware มีความซับซ้อนเกินไป จนอาจทำให้เกิดการเรียกตัวเองซ้ำ ๆ ไปเรื่อย ๆ เป็นลูปที่ไม่มีวันสิ้นสุดได้ ด้วยเหตุนี้จึงมีการสร้างตัวของ Header ที่มีชื่อว่า “X-Middleware-SubRequest” มาใช้เพื่อจัดการปัญหาตรงนี้นั้นเอง
X-Middleware-SubRequest มีไว้ทำอะไร?
X-Middleware-SubRequest เป็น Header ที่เอาไว้ใช้กับ Middleware ซึ่งมันจะมีหน้าที่หลักนั้นคือการป้องกันการวนลูปใน Middleware โดยข้ามการใช้งานตัวของ Middleware ไปในกรณีที่มีการเรียกใช้งานตัวของ Middleware ไปแล้ว หรือเรียกซ้ำเกินจำนวนที่กำหนด และใช่ครับเมื่อมันมีหน้าที่สำคัญขนาดนี้ก็ไม่รอดและถูกใช้เป็นช่องทางการโจมตีของช่องโหว่นี้นั้นเอง
อธิบายช่องโหว่ CVE-2025–29927
จากคำอธิบายของนักวิจัย “Yasser Allam” และ “Rachid Allam” ที่เป็นผู้ค้นพบช่องโหว่นี้และได้มีการเผยแพร่เมื่อ 21 มีนาคมที่ผ่านมา โดยช่องโหว่ดังกล่าวมีผลกระทบแค่แอปพลิเคชันที่มีการใช้งานตัว Middleware เท่านั้น ซึ่งจะพบช่องโหว่นี้ได้ในเวอร์ชัน
· Next.js 15.x < 15.2.3
· Next.js 14.x < 14.2.25
· Next.js 13.x < 13.5.9
· Next.js 12.x < 12.3.5
โดยมีสาเหตุจาก

รูปจาก: https://github.com/vercel/next.js/blob/v12.0.7/packages/next/server/next-server.ts
จากโค้ด แอปพลิเคชันที่มีการใช้งาน Middleware จะไปเรียกฟังก์ชัน “runMiddleware” ขึ้นมาทำงาน โดยในฟังก์ชันดังกล่าวจะมีการตรวจสอบว่าค่าที่อยู่ใน Header “X-Middleware-SubRequest” ของ Request นั้นตรงกับค่าที่มันกำหนดไว้ในตัวแปร “middlewareInfo.name” ไหม ถ้าตรงกันก็ให้ Request นั้นข้ามการทำงานของ Middleware ไปเลย นั้นหมายความว่าแค่ใส่ค่าใน Header ให้ถูกต้องตามที่ตัวฟังก์ชันกำหนด ก็จะสามารถทำการข้ามการทำงานทั้งหมดของ Middleware ไปได้และสำหรับค่าที่ต้องใส่ให้ถูกต้องนั้นจะขึ้นอยู่กับเวอร์ชันของ Next.js โดยค่านั้นจะมาจาก “ชื่อตำแหน่งที่อยู่ของ Middleware + ชื่อไฟล์” นั้นเอง
สำหรับวิธีการโจมตีจะแบ่งเป็นหลัก ๆ ด้วยเวอร์ชันของ Next.js ได้แก่
Next.js เวอร์ชันที่มีช่องโหว่ต่ำกว่า 12.2 ลงมา
ในเวอร์ชันนี้โดยปกติแล้วตำแหน่งของ Middleware นั้นจะวางอยู่ภายในโฟลเดอร์ “pages” และจะใช้ชื่อไฟล์ว่า “_middleware.js” เมื่อนำชื่อมารวมกันจะ Header ประมาณนี้
X-Middleware-SubRequest: pages/_Middleware
แต่ในเวอร์ชันนี้มีการอนุญาตให้วางไฟล์ “_middleware.js” ซ้อนกันหลายระดับได้ (ภายใต้โฟลเดอร์ pages) และแต่ละไฟล์มีลำดับการทำงานที่กำหนดไว้ตามลำดับของ path ดังนั้นในเวอร์ชันนี้อาจจะมีผลลัพธ์การโจมตีได้หลากหลายอย่างเช่น ถ้าเราจะข้ามการตรวจที่พาธ “/admin/secret/super secret” จะมีความเป็นไปได้อยู่ด้วยกันทั้งหมด 3 แบบในการใส่ค่าใน Header นั้นคือ
X-Middleware-SubRequest: pages/_middleware
หรือ
X-Middleware-SubRequest: pages/admin/_middleware
หรือ
X-Middleware-SubRequest: pages/admin/secret/_middleware
Next.js เวอร์ชันที่มีช่องโหว่ตั้งแต่ 12.2 จนถึง 14.1.4
ในเวอร์ชันหลังจากนี้จะมีการใช้ชื่อไฟล์เป็น “middleware.ts” ไม่มี “_ (underscore)” นำหน้าแล้วและพาธที่สามารถวางไฟล์ได้จะมีแค่ “/ (root path)” และ “/src” เท่านั้นทำให้ค่าใน Header จากที่ต้องคาดเดาในวิธีก่อนหน้าจะเหลือแค่
X-Middleware-SubRequest: middleware
หรือ
X-Middleware-SubRequest: src/middleware
เพียงเท่านั้น
Next.js เวอร์ชันที่มีช่องโหว่ตั้งแต่ 14.2.0 ขึ้นไป
ในเวอร์ชันนี้จะมีความเปลี่ยนแปลงอยู่เล็กน้อยนั้นคือ

รูปจาก: https://github.com/vercel/next.js/blob/v14.2.0/packages/next/src/server/web/sandbox/sandbox.ts
จากโค้ด จะเห็นได้ว่ามีการเพิ่มเงื่อนไขนับจำนวนของการทำงาน Middleware เข้ามา โดยต้องมีการทำงานซ้ำเกิน 5 ครั้งขึ้นไปถึงจะสามารถข้ามการทำงานได้ เพราะฉะนั้น ถ้าจะข้ามการทำงานของ Middleware ในเวอร์ชันนี้ต้องทำการใส่ค่าใน Header เป็น
X-Middleware-SubRequest: middleware:middleware:middleware:middleware:middleware
หรือ
X-Middleware-SubRequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware
ตัวอย่างการโจมตีช่องโหว่ CVE-2025–29927
เอาละครับหลังจากที่เราได้รู้ข้อมูลคร่าว ๆ ของช่องโหว่นี้กันไปแล้ว และผมคาดว่าหลาย ๆ คนน่าจะยังไม่เห็นภาพเพราะฉะนั้นเรามาลองโจมตีช่องโหว่นี้กันดูจริง ๆ กันดีกว่า
ขั้นตอนแรกเราต้องทำการสร้างเว็บไซต์ด้วย Next.js เวอร์ชันที่มีช่องโหว่เสียก่อน ซึ่งทางผมได้เลือกใช้งานเวอร์ชัน “Next.js 14.1.4” และลองทำการเข้าใช้งานเว็บเพื่อดูว่าสามารถใช้งานได้จริง

รูปที่ 1
ต่อมาทำการสร้างไฟล์ “Middleware.js” และตั้งค่าให้มันตรวจสอบ Request จาก User ที่พาธ “/secret” โดยกำหนดไว้ว่าถ้าไม่มี Header “Authorization: oo ee aa ee oo aa oo ee” จะไม่ให้เข้าถึงพาธดังกล่าวได้

รูปที่ 2
ที่นี้ทำการลองเข้าพาธ “/secret” ด้วยเครื่องมือ Burp ดูจะเห็นได้ว่าไม่สามารถเข้าถึงได้ เพราะแอปพลิเคชันมีการตั้งค่าไว้ว่าต้องมี Credential ที่กำหนดก่อนเท่านั้น ถึงจะเข้าใช้งานได้

รูปที่ 3
ลองเข้าพาธ “/secret” อีกรอบด้วย Header “Authorization: oo ee aa ee oo aa oo ee” ดู จะเห็นได้ว่าสามารถเข้าใช้งานได้ปกติ นั้นหมายความว่าการทำงานของ Middleware สามารถทำงานได้ปกติ

รูปที่ 4
เอาละหลังจากทดสอบความพร้อมของแอปพลิเคชันกันไปแล้ว ที่นี้ก็ถึงเวลาโจมตีดูว่าสามารถโจมตีได้จริงไหม และจากที่ผมได้อธิบายไปในหัวข้อก่อนหน้านั้น ในแอปพลิเคชันนี้เข้าข่ายการโจมตีด้วย Header “X-Middleware-SubRequest: middleware” เพราะว่ามีการใช้ Next.js เวอร์ชัน 14.1.4 และตัว Middleware ของเรานั้นทำงานอยู่ที่พาธ “/ (root path)” เมื่อทุกอย่างพร้อมแล้วเรามาลองโจมตีดู

รูปที่ 5
จากรูปที่ 5 จะเห็นได้เลยว่าเมื่อเราใส่ Header เป็น “X-Middleware-SubRequest: middleware” และเรียกใช้งานพาธ “/secret” เราสามารถที่จะข้ามการทำงานของ Middleware ได้สำเร็จ
วิธีการป้องกันช่องโหว่ CVE-2025–29927
ในปัจจุบันทาง Official ได้มีการปล่อยอัปเดตเพื่อแก้ไขช่องโหว่ CVE-2025–29927 ออกมาแล้วโดยจะเป็น Next.js เวอร์ชันดังนี้
· Next.js 15.2.3 หรือสูงกว่า
· Next.js 14.2.25 หรือสูงกว่า
· Next.js 13.5.9 หรือสูงกว่า
· Next.js 12.3.5 หรือสูงกว่า
และแน่นอนสำหรับวิธีป้องกันที่เห็นผลชัดเจนและดีในระยะยาวที่สุดคืออัปเดตแพตช์ Next.js เป็นเวอร์ชันที่แก้ไขแล้วตามข้างต้น แต่ว่าถ้าเกิดไม่สามารถทำการอัปเดทแพตช์ Next.js เป็นเวอร์ชันที่ปลอดภัยได้ไม่ว่าจะด้วยเหตุผลใดก็ตาม ก็แนะนำให้ทำการเพิ่มการตรวจสอบที่ Web Application Firewall (WAF), Reverse Proxy หรือ Load Balancer ที่อยู่หน้าแอปพลิเคชันให้ทำการ “บล็อก” หรือ “ลบ” Request ที่มี Header “X-Middleware-SubRequest” ทิ้งไปก่อนที่จะส่งมาถึงเซิร์ฟเวอร์ของเรานั้นเอง
และจบกันไปแล้วนะครับสำหรับบทความนี้กับช่องโหว่ CVE-2025–29927 เราจะเห็นได้ว่าเงื่อนไขที่สำคัญที่สุดในการโจมตีของช่องโหว่นี้คือมีการใช้งาน Middleware ในการเป็นตัวกลางตรวจสอบ Request ต่าง ๆ ที่เข้ามาจาก User นั้นเองครับ เพราะฉะนั้นแล้วใครก็ตามที่ผ่านทางมาเห็นและใช้งานตัวเฟรมเวิร์ก Next.js คู่กับ Middleware อยู่ ก็ลองสำรวจดูนะครับว่า Next.js ที่เราได้ใช้นั้นเป็นเวอร์ชันที่โดนช่องโหว่ตัวนี้หรือไม่ สุดท้ายนี้ตัวผมก็ขอให้ทุกท่านสนุกกับการอ่านบทความนี้นะครับ แล้วเจอกันใหม่ในหัวข้อถัดไปครับ
References:
https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-Middleware
https://snyk.io/blog/cve-2025-29927-authorization-bypass-in-next-js-Middleware/
https://securitylabs.datadoghq.com/articles/nextjs-Middleware-auth-bypass/
https://jfrog.com/blog/cve-2025-29927-next-js-authorization-bypass/
https://projectdiscovery.io/blog/nextjs-Middleware-authorization-bypass