Skip to content

fix: path traversal, arbitrary file read, and weak session secret in Node server#1387

Open
mohammadmseet-hue wants to merge 1 commit into
cdapio:developfrom
mohammadmseet-hue:fix/server-security-vulnerabilities
Open

fix: path traversal, arbitrary file read, and weak session secret in Node server#1387
mohammadmseet-hue wants to merge 1 commit into
cdapio:developfrom
mohammadmseet-hue:fix/server-security-vulnerabilities

Conversation

@mohammadmseet-hue
Copy link
Copy Markdown

Summary

This PR addresses three security vulnerabilities in the CDAP UI Node.js server:

1. Path Traversal via WebSocket template-config Message (High)

File: server/aggregator.jspushConfiguration()

The templateid and pluginid parameters from WebSocket messages are concatenated directly into file paths and read with fs.readFileSync() without any validation:

filePaths.push(
  __dirname + '/../templates/' + templateid + '/' + pluginid + '.json',
  __dirname + '/../templates/common/' + pluginid + '.json'
);
configString = fs.readFileSync(filePaths[i], 'utf8');

An attacker with a valid session token can send templateid: "../../etc" and pluginid: "passwd" to read arbitrary .json-parseable files from the server filesystem. The file contents are returned through the WebSocket connection in the response payload.

Fix: Validate both templateid and pluginid against a strict allowlist pattern (/^[a-zA-Z0-9_-]+$/) before constructing file paths. Reject requests with a 400 status if validation fails.

2. Arbitrary File Read via POST /updateTheme (High)

Files: server/express.js, server/uiThemeWrapper.js

The /updateTheme endpoint accepts a uiThemePath in the request body and passes it to extractUITheme(), which uses require() (via __non_webpack_require__) to load the file. The loaded content is then exposed at GET /ui-theme.js as a JavaScript global:

// express.js — loaded content served to all visitors
res.send(`window.CDAP_UI_THEME = ${JSON.stringify(uiThemeConfig)};`);

An attacker with a session token can load arbitrary files (.js, .json, .node) from the server, and their contents become publicly readable at /ui-theme.js.

Fix: Validate that the resolved theme path is within the allowed themes directory (server/config/themes/) and has a .json extension before loading.

3. Hardcoded Session Secret (Medium)

Files: server/token.mjs, server/config/development/cdap.json

The development configuration ships with "session.secret.key": "sample-secret-key-for-encryption". If this value is not overridden in production, all session tokens become predictable — any attacker who knows this default can forge valid session tokens and bypass session validation on all protected endpoints.

Fix: Detect the insecure default value at startup and replace it with a cryptographically random secret generated via crypto.randomBytes(). Log a warning to prompt operators to configure a proper secret.

Related

  • PR #16098 on cdapio/cdap addresses similar issues in the backend

Test Plan

  • Verify WebSocket template-config requests with valid templateid/pluginid still work
  • Verify template-config requests with ../ in templateid or pluginid are rejected with 400
  • Verify POST /updateTheme with a path inside server/config/themes/ still works
  • Verify POST /updateTheme with ../../etc/passwd or /etc/passwd is rejected with 400
  • Verify session tokens are generated and validated correctly after the secret fallback change
  • Verify the warning log appears when using the default secret

…cret

1. Path traversal via WebSocket template-config: Validate templateid and
   pluginid parameters against a strict allowlist pattern (alphanumeric,
   hyphens, underscores only) before using them to construct file paths
   in pushConfiguration(). Previously, values like "../../etc" could
   traverse outside the templates directory via fs.readFileSync.

2. Arbitrary file read via POST /updateTheme: Validate that the
   uiThemePath resolves within the allowed themes directory and has a
   .json extension before passing it to extractUITheme(), which uses
   require() to load the file. This prevents reading arbitrary server
   files and exposing their contents at GET /ui-theme.js.

3. Hardcoded session secret: The development config ships with
   "sample-secret-key-for-encryption" as session.secret.key. If this
   default value is used in production, session tokens become
   predictable. Generate a cryptographically random fallback secret at
   process startup when no strong key is configured.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant