A Next.js middleware authentication bypass (CVE-2025-29927) Writeup: Hackdonalds Challenge (Intigriti)

3 min read
A Next.js middleware authentication bypass (CVE-2025-29927)  Writeup: Hackdonalds Challenge (Intigriti)

Next.js Middleware Authentication Bypass (CVE-2025-29927)

Classic XML External Entity (XXE) injection

This combination ultimately allowed me to read system files and retrieve the flag from the server.

🔍 Recon – The Starting Point

We were given the URL: 29d09927-bd8a-4c8c-b25a-3aaf996cf5ef.png

Visiting the site showed a clean interface with a mysterious Admin section. Clicking it led to a login page that required a secret key. Instead of trying to brute-force the key, I opted for some recon.

⚙️ Wappalyzer to the Rescue

I used Wappalyzer to identify the technologies behind the app. It revealed that the application is built using Next.js. ecc937c0-e4a6-40d8-8aac-0fab75bea1e2.png

Immediately, a recent CVE came to mind: CVE-2025–29927 – A vulnerability in Next.js middleware that allows bypassing authentication by injecting a special header:

X-Middleware-Subrequest: middleware

👉ProjectDiscovery writeup

Bypassing Auth with Next.js Middleware Vulnerability

I opened Burp Suite, navigated to the https://hackdonalds.intigriti.io/admin page, and captured the request using Burpsuite. As expected, the server redirected me to /login due to the missing secret key

aab0592e-03d4-40f5-bce3-e88d4f91367f.png

So I added the magic header: X-Middleware-Subrequest: middleware Then forwarded the request. 🎉 Boom! I was in. The middleware treated the request as internal and let me bypass the authentication entirely.

8683a6be-c1c2-430e-bf9f-0c97efa71d9d.png

🔁 Making Auth Persistent (No Intercepting Every Time)

While this worked, refreshing the page removed the header — and I got logged out again. To fix this: I went to Burp Suite → Proxy → Match and Replace

Left the Match field empty

Set Replace to: X-Middleware-Subrequest: middleware then saved the rule

d7f2a8a8-3205-4a11-afe4-28d24460023e.png

Now every request included the bypass header automatically.

Exploring the Ice Cream Machine

Inside the admin panel, I found an endpoint called /ice-cream-machine

5fc08514-f7bc-4556-951e-cf640f42652d.png

This page showed machine statuses (Online/Offline). Clicking on an online machine revealed a custom XML input form that let you query machine data.

Any time I see XML input as a security researcher, my radar pings 🔔 Intigriti Blog for XXE

f58fd06a-c16d-4521-a0e2-8889c9134691.png

XXE Attack: Reading /etc/passwd

My instinct told me this XML parser might be vulnerable to XXE. So I tested with a payload like this:

XXE Payload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE machine [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<machine>
  <id>1</id>
  <name>&xxe;</name>
  <temperature>-18</temperature>
  <mixLevel>75</mixLevel>
  <lastMaintenance>2025-03-15</lastMaintenance>
  <cleaningSchedule>Daily</cleaningSchedule>
</machine>

df9a3f7d-1a48-4100-a4d1-de1a0a37b03b.png

🚨 It worked! The contents of /etc/passwd were returned in the response — confirming XXE vulnerability.

🏁 Final Step – Locating the Flag

While /etc/passwd proved file read worked, the flag wasn’t there. So I thought if this is a MERN stack app, then core content is often stored under /app, and most devs keep /app as there main application directory and in MERN a single file that always exists package.json file. so I decided to check the package.json file content first.

I updated the payload to:

XXE Payload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE machine [
  <!ENTITY xxe SYSTEM "file:///app/package.json">
]>
<machine>
  <id>1</id>
  <name>&xxe;</name>
  <temperature>-18</temperature>
  <mixLevel>75</mixLevel>
  <lastMaintenance>2025-03-15</lastMaintenance>
  <cleaningSchedule>Daily</cleaningSchedule>
</machine>

8b0b884b-6d6f-444c-b69e-8659edf70425.png

📦 Boom again! The file was fetched and displayed the flag, completing the challenge.

🧠 What We Learned

Vulnerability Impact

  1. CVE-2025-29927 Bypassed middleware auth
  2. ✅ XXE Injection Local file disclosure
  3. ✅ Logical guesswork Found and read package.json
  4. 🔐 Just because modern frameworks are in use doesn’t mean old-school bugs like XXE can’t sneak in!

🚀 Thanks for Reading!

If you enjoyed this writeup, feel free to connect or leave a comment.

Happy hacking! 🐱‍💻🔓 ~ Vinit Prajapati**

Want to write a blog?

Unfold your thoughts and let your ideas take flight in the limitless realm of cyberspace. Whether you're a seasoned writer or just starting, our platform offers you the space to share your voice, connect with a creative community and explore new perspectives. Join us and make your mark!

Follow us on social media

Cyber Unfolded Light Logo
Copyright © 2025 CYUN. All rights reserved.