BTC
ETH
SOL
BNB
GOLD
XRP
DOGE
ADA
Back to home
Security

[LOW] Security Advisory: Signal K Server: Arbitrary Prototype Read via `from` Field Bypass (signalk-server)

Signal K Server, a Node.js application for sharing marine sensor data via the open Signal K standard, has a security flaw that lets authenticated users read internal JavaScript prototype properties.

Signal K Server, a Node.js application for sharing marine sensor data via the open Signal K standard, has a security flaw that lets authenticated users read internal JavaScript prototype properties. Attackers bypass a prototype pollution guard by targeting the unmonitored from field in JSON Patch operations. This exposes Node.js internals like function references but stops short of code execution.

The vulnerability hits the /signalk/v1/applicationData/... endpoint, which processes JSON Patches to modify stored app data. Developers added a guard against prototype pollution, but it only scans the path property. Operations like copy and move pull data from the from path, which goes unchecked. An attacker sets from to /__proto__/toString and copies it to a safe path like /stolen. The patch applies, dumping prototype data into the user’s application storage.

Root Cause in Code

The issue stems from src/interfaces/applicationData.js. The guard function ignores from:

const DANGEROUS_PATH_SEGMENTS = ['__proto__', 'constructor', 'prototype']

function isPrototypePollutionPath(pathString) {
  const segments = pathString.split(/[./]/)
  return segments.some((seg) => DANGEROUS_PATH_SEGMENTS.includes(seg))
}

function hasPrototypePollutionPatch(patches) {
  return patches.some(
    // Only checks patch.path, ignores patch.from
    (patch) => patch.path && isPrototypePollutionPath(patch.path)
  )
}

Before applying patches with jsonpatch.apply(applicationData, req.body), the server calls this check. Since from paths like /__proto__/someProperty slip through, attackers read global prototype state.

Proof of Concept

Test the guard first with a blocked payload:

curl -X POST http://localhost:3000/signalk/v1/applicationData/global/testapp/1.0 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '[{"op": "add", "path": "/__proto__/polluted", "value": "hacked"}]'

Response: 400 Bad Request – invalid patch path. Now the bypass:

curl -X POST http://localhost:3000/signalk/v1/applicationData/global/testapp/1.0 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '[{"op": "copy", "from": "/__proto__/toString", "path": "/stolen"}]'

Response: 200 OK. Check the stored data; it now holds a reference to the toString function from the prototype.

Fix and Implications

Patch the guard to check both fields:

function hasPrototypePollutionPatch(patches) {
  return patches.some(
    (patch) =>
      (patch.path && isPrototypePollutionPath(patch.path)) ||
      (patch.from && isPrototypePollutionPath(patch.from))
  )
}

This is rated low severity—no remote code execution, no privilege escalation beyond reading prototypes. Signal K servers run on boats or yachts, aggregating data from GPS, AIS, engines, and sensors. Authenticated users might include crew or apps with API tokens. Exfiltrating internals like toString or other prototype methods violates isolation but offers little direct harm. No sensitive boat data leaks; it’s JavaScript engine guts.

Why does this matter? Prototype pollution remains a top Node.js attack vector—OWASP lists it as a top 10 risk. Even reads can chain into worse issues if the app mishandles polluted data elsewhere. Signal K Server, used in production on vessels worldwide (over 10,000 instances per their GitHub stats), demands tight security. Developers fixed similar issues before, but overlooking from shows incomplete audits. Vessel operators: update to a patched version if available, rotate tokens, and audit app data storage. For devs, always validate all path fields in JSON Patch handlers—jsonpatch libs resolve them natively, so guards must match.

Bottom line: straightforward fix, low real-world risk, but a reminder that half-measures on prototype pollution invite trouble. Check your Signal K setup; if exposed, any authenticated user can poke the JS underbelly.

April 3, 2026 · 3 min · 5 views · Source: GitHub Security

Related