Skip to content

Upstream merge from vscode-server - #15335

Open
mbaynton wants to merge 3 commits into
mainfrom
localhost-port-isolation
Open

Upstream merge from vscode-server#15335
mbaynton wants to merge 3 commits into
mainfrom
localhost-port-isolation

Conversation

@mbaynton

@mbaynton mbaynton commented Aug 4, 2026

Copy link
Copy Markdown

Upstream merge from vscode-server, bringing in rstudio/vscode-server#389.

Summary

Verifies the localhost port a /proxy/<port>/ request targets is owned by the requesting session's own user before proxying HTTP or WebSocket traffic to it. This closes a cross-user isolation gap on multi-user Workbench hosts (rstudio-pro#11470): without this check, one user's session could proxy into a port bound by another user's process on the same host.

Ownership is determined by reading /proc/net/tcp[6] for the listening socket's uid -- the same kernel data rserver's NETLINK_SOCK_DIAG-based fix relies on, without adding a native dependency. Enforcement fails open when unavailable (non-Linux, root sessions, unreadable /proc) and fails closed on a uid mismatch, returning 403 for HTTP requests and destroying the socket for WebSocket upgrades. A new --www-proxy-localhost-verify-port-owner flag disables the check if an environment needs to.

New tests (socketOwnership.vitest.ts, webClientServer.vitest.ts) are ported as Vitest rather than upstream's Mocha .test.ts, per Positron's convention for new Positron-owned server code.

Other commits on upstream/main since the last pull (#13497) were triaged and left out:

Reason Commits
Already implemented in Positron
rstudio.rstudio-workbench version bumps; Positron's product.json already pins an equal or newer version
  • rstudio/vscode-server#377
  • rstudio/vscode-server#365
CI automation only (.github/, Jenkinsfile)
  • rstudio/vscode-server#393
  • rstudio/vscode-server#390
  • rstudio/vscode-server#372
  • rstudio/vscode-server#369

Release Notes

New Features

  • N/A

Bug Fixes

  • Isolate /proxy/ port access to the requesting session's own user on multi-user Workbench hosts

Validation Steps

@:workbench @:web @:jupyter

  1. Start Positron Server / Workbench with two sessions running as different users on the same host.
  2. Have user B start a process listening on a localhost port (e.g. python -m http.server 8123).
  3. As user A, request /proxy/8123/ through the Workbench-fronted URL -- expect a 403 "Access to the requested port is forbidden." response instead of a proxied response.
  4. As user B, request /proxy/8123/ (their own port) -- expect normal proxying to succeed.
  5. Verify a WebSocket upgrade to another user's port is refused (socket destroyed, no proxy connection established), and to your own port succeeds.
  6. Verify --www-proxy-localhost-verify-port-owner=0 disables the check (proxying succeeds regardless of port ownership).

Brings in:
- rstudio/vscode-server#389: Isolate /proxy/ port access to the requesting session's own user

Verifies the localhost port a /proxy/<port>/ request targets is owned
by the session's uid before proxying HTTP or WebSocket traffic to it,
closing a cross-user isolation gap on multi-user Workbench hosts
(rstudio-pro#11470, vscode-server#388). Ownership is determined by
reading /proc/net/tcp[6] for the listening socket's uid, without
adding a native dependency. Enforcement fails open when unavailable
(non-Linux, root sessions, unreadable /proc) and fails closed on a
uid mismatch, returning 403 for HTTP and destroying the socket for
WebSocket upgrades. A --www-proxy-localhost-verify-port-owner flag
disables the check if needed.

Tests are ported as Vitest (socketOwnership.vitest.ts,
webClientServer.vitest.ts) rather than upstream's Mocha .test.ts,
per Positron's convention for new Positron-owned server code.
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

E2E Tests 🚀
This PR will run tests tagged with: @:critical @:workbench @:web @:jupyter

Why these tags?
Tag Source
@:critical Always runs (required)
@:workbench PR description
@:web PR description
@:jupyter PR description

More on automatic tags from changed files.

readme  valid tags

@mbaynton

mbaynton commented Aug 4, 2026

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

…erver.ts

webClientServer.ts computes APP_ROOT at module load via FileAccess.asFileUri(''),
which throws unless globalThis._VSCODE_FILE_ROOT is set. Bootstrap entry points set
this normally; a plain Vitest run doesn't go through one.
The "fails open" test read the real process uid via process.getuid(), but
production code intentionally skips its warning log when uid === 0. CI
containers commonly run as root, so the test failed there while passing
locally. Stub process.getuid to a fixed non-zero uid instead.
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