[Eclipse Theia] Arbitrary file read via file-download endpoints (no path containment)

Basic information

Project name: Eclipse Theia

Project id: ecd.theia

What are the affected versions?

Confirmed on 1.72.3 and current master (1.73.0). Likely present in all prior releases that ship the same endpoints.

Details of the issue

  • CWE-22: Improper Limitation of a Pathname to a Restricted Directory (Path Traversal)
  • CWE-36: Absolute Path Traversal
  • Impact: CWE-200 (Exposure of Sensitive Information)
  • Aggravating: CWE-306 (Missing Authentication for Critical Function); see paragraph about authentication, below

The Theia backend exposes HTTP file-download endpoints that convert a client-supplied URI directly to a filesystem path and stream the file, without any restriction to the workspace (or any allow-listed root). A client can therefore read any file readable by the backend process, including files entirely outside the opened workspace (e.g. /etc/hosts, SSH keys, tokens, other users' files on a shared/hosted deployment).

  1. Standalone GET /file endpoint: packages/filesystem/src/node/download/file-download-endpoint.ts (handler registered via app.get('/file', ...)):
       const uri = url.parse(request.url).query;      // client-controlled
       const fsPath = FileUri.fsPath(decodeURIComponent(uri));
       response.sendFile(fsPath);                     // no containment check
  1. /files/ single-file handler: packages/filesystem/src/node/download/file-download-handler.ts (SingleFileDownloadHandler.handle):
       const uri = new URI(query.uri).toString(true); // client-controlled
       const filePath = FileUri.fsPath(uri);
       // fs.stat(filePath) + stream; directories are tar-archived
       // no check that filePath is inside a workspace/allowed root

Neither path is normalized against or confined to the workspace roots.

In browser deployments, the connection token is enforced only on WebSocket upgrades. The corresponding Express middleware (packages/core/src/node/hosting/browser-connection-token.ts, BrowserConnectionTokenBackendContribution.expressMiddleware) does not reject tokenless HTTP requests; it only (re)issues the cookie and calls next(). Consequently, these HTTP endpoints are reachable without a valid token. (Electron uses a separate ElectronSecurityToken.)

Steps to reproduce

With the browser example (or any Theia-based app) running, in a terminal on your host system do:

   $ curl 'http://<host>:3000/file?file%3A%2F%2F%2Fetc%2Fhosts'

This then returns the server's /etc/hosts, a file outside any workspace that any connected frontend has open.

Do you know any mitigations of the issue?

Excluding the @theia/filesystem package from the Theia-based application would not cause the affected service endpoint not to be present at run-time.