Security¶
Overview¶
TermBeam provides access to a real shell on your machine. Security is critical.
Threat Model¶
TermBeam exposes a real shell over the network. The risk depends entirely on how you run it. Understanding the operating modes below helps you make informed decisions.
Operating Modes¶
TermBeam has three access layers that combine to determine your risk profile:
| Mode | Command | Who Can Connect | Auth | Risk |
|---|---|---|---|---|
| Default (private tunnel) | termbeam |
Only you (Microsoft login + password) | Auto-password + tunnel owner auth | ✅ Low |
| Public tunnel | termbeam --public |
Anyone with the URL + password | Auto-password | ⚠️ Medium |
| LAN-only (localhost) | termbeam --no-tunnel |
Local machine only | Auto-password | ✅ Low |
| LAN-only (all interfaces) | termbeam --no-tunnel --lan |
Any device on your network | Auto-password | ⚠️ Medium |
| Localhost, no password | termbeam --no-tunnel --no-password |
Local processes only | None | ⚠️ Medium |
| LAN, no password | termbeam --no-tunnel --no-password --lan |
Anyone on your network | None | 🔴 High |
--public --no-password is blocked
The CLI refuses to start with a public tunnel and no password.
Private Tunnel (Default)¶
The default mode creates an ephemeral Azure DevTunnel that requires two layers of authentication:
- Microsoft account login — only the tunnel owner can access the URL
- TermBeam password — auto-generated on each run
This is the safest way to access your terminal remotely. The tunnel URL is HTTPS, the connection is encrypted end-to-end, and the URL is unguessable.
Public Tunnel¶
With --public, the tunnel URL is accessible to anyone who has it — no Microsoft login required. Password authentication is still enforced. This mode is useful for sharing temporary access, but the terminal is internet-accessible and protected only by the password and rate limiting (5 attempts/min/IP).
LAN Exposure¶
With --lan or --host 0.0.0.0, TermBeam binds to all network interfaces. Any device on your local network can reach the server. On trusted home networks this may be acceptable; on shared or public networks (coffee shops, coworking spaces, hotel Wi-Fi) this is risky.
Safe Defaults¶
Out of the box, TermBeam is configured conservatively:
- ✅ Password auto-generated — a strong random password is created on every run
- ✅ Localhost bind — server listens on
127.0.0.1only - ✅ Private tunnel — tunnel requires Microsoft account login (owner-only)
- ✅ Ephemeral tunnel — tunnel URL is deleted when TermBeam exits
- ✅ Security headers — X-Frame-Options, CSP, no-store, nosniff on all responses
- ✅ Rate-limited login — 5 attempts per minute per IP
- ✅ httpOnly cookies — tokens not accessible to JavaScript
- ✅ WebSocket origin validation — cross-origin connections rejected
- ✅ Shell path validation — only detected shells allowed
Dangerous Modes¶
The following flags increase your attack surface. Use them only when you understand the trade-offs.
| Flag | Effect | When Acceptable |
|---|---|---|
--public |
Removes Microsoft login from tunnel | Sharing temporary access with someone without a Microsoft account |
--no-password |
Removes password auth | Localhost-only on a single-user machine |
--lan / --host 0.0.0.0 |
Binds to all interfaces | Trusted home network with password enabled |
--lan --no-password |
LAN-accessible, no auth | Not recommended |
Quick Safety Checklist¶
Before running TermBeam, verify:
- [ ] Password is enabled — don't use
--no-passwordunless localhost-only on a trusted machine - [ ] Tunnel is private — don't use
--publicunless you specifically need anonymous tunnel access - [ ] Bind is localhost — don't use
--lanunless you need LAN access on a trusted network - [ ] Close when done — TermBeam is not a daemon; don't leave it running unattended
- [ ] Check the network — on shared/public Wi-Fi, stick to defaults
Work vs Personal Machine¶
Personal machine (home network): Default settings are appropriate. If you need LAN access (e.g., phone on the same Wi-Fi), --lan with the auto-generated password is reasonable.
Work machine (corporate network): Use defaults (private tunnel + auto-password). Avoid --public and --lan on corporate networks. TermBeam is a development tool, not a production remote access solution.
Not Recommended
- Running TermBeam with
--publicon machines with access to customer data or secrets - Using
--no-password --lanon any network you don't fully control - Leaving TermBeam running unattended for extended periods
- Using TermBeam as a replacement for SSH, VPN, or proper remote access infrastructure
Security Features¶
Authentication¶
- Password is auto-generated by default; can also be set via
--passwordorTERMBEAM_PASSWORD - Tokens are cryptographically random (32 bytes, hex-encoded)
- Tokens expire after 24 hours
- Session IDs use 128-bit entropy (
crypto.randomBytes(16), hex-encoded) - Stored in httpOnly cookies (not accessible via JavaScript)
- Cookie uses
sameSite: strictto prevent CSRF - Cookie
Secureflag is set dynamically based on the request protocol — enabled automatically when accessed over HTTPS (including viaX-Forwarded-Protofrom tunnel proxies), omitted for plain HTTP - API routes (
/api/*) always return JSON401/429responses. UI routes redirect to the login page.
QR Code & Share Auto-Login (Share Tokens)¶
- On startup, a share token is generated and embedded in the QR code URL as
?ott=<token> - Scanning the QR code sets a full session cookie and redirects to the clean URL — no password typing required
- Share tokens are one-time use — consumed on first successful login to prevent replay attacks
- Share tokens expire after 5 minutes
- The share button generates a fresh share token via
GET /api/share-token(authenticated endpoint) - If the user already has a valid session cookie, a repeated
?ott=request simply redirects without re-validating - Raw password is never embedded in any URL
Shell Path Validation¶
- The
POST /api/sessionsendpoint validates theshellparameter against the list of detected shells on the host - Arbitrary shell paths are rejected — only shells returned by
GET /api/shellsare allowed - The
cwdparameter is validated to be an existing, absolute directory path
Image Upload Validation¶
- The
POST /api/uploadendpoint validates uploaded images using multiple checks: - Content-Type must be an
image/*MIME type - Magic bytes are verified against the declared content type to prevent spoofing
- File size is capped at 10 MB (returns HTTP 413 if exceeded)
- Uploaded files are stored with UUID-generated filenames to prevent path traversal
- Requires authentication to upload or access uploaded files
Terminal Resize Bounds¶
- WebSocket
resizemessages validate dimensions: columns must be 1–500, rows must be 1–200 - Values outside these bounds are silently ignored, preventing DoS via extreme terminal sizes
WebSocket Origin Validation¶
- WebSocket connections include Origin header checks
- Cross-origin connections are rejected (close code
1008) unless one side islocalhost - Prevents malicious websites from connecting to a local TermBeam instance
Rate Limiting¶
- Login endpoint limited to 5 attempts per minute per IP
- WebSocket auth limited to 5 attempts per minute per IP
- Returns HTTP 429 (or WebSocket close) when exceeded
HTTP Security Headers¶
Every response includes:
| Header | Value | Purpose |
|---|---|---|
X-Content-Type-Options |
nosniff |
Prevent MIME sniffing |
X-Frame-Options |
DENY |
Prevent clickjacking |
Content-Security-Policy |
script/style/connect sources | Prevent XSS |
Cache-Control |
no-store |
Prevent caching |
Referrer-Policy |
no-referrer |
No referrer leaks |
Client-Side Features¶
The following UI features are entirely client-side and introduce no new server-side attack surface:
- Command completion notifications — uses the browser Notification API, which requires explicit user permission (opt-in). No data is sent to external services; notifications are generated locally in the browser.
- Terminal search — runs in the browser via the xterm.js SearchAddon. Search queries never leave the client.
- Command palette — a client-side UI panel that triggers existing actions. No new endpoints or permissions required.
Network Binding¶
- Default: Binds to
127.0.0.1(localhost only) - Use
--lanor--host 0.0.0.0to allow LAN access - The tunnel feature handles TLS via Azure DevTunnels
Tunnel Token Expiry¶
- DevTunnel auth tokens expire periodically (a Microsoft-imposed limitation)
- The DevTunnel CLI handles token refresh automatically via OAuth refresh tokens
- If the refresh token itself expires, TermBeam enters auth-wait mode, pausing tunnel operations until the user runs
devtunnel user loginon the host machine - Once re-authenticated, the watchdog reconnects the tunnel automatically — no server restart required
Best Practices¶
Never Run Without a Password on a Public Network
Without authentication, anyone on the network can access your terminal with your user permissions.
- Password is on by default — use
--no-passwordonly for trusted localhost scenarios.--publicrequires password authentication and will refuse to start without it - Localhost is the default — use
--lanonly when you need LAN access - Tunnel access is private by default — only you (the tunnel owner) can access it via Microsoft login. Use
--publicto allow public access, or--no-tunnelfor LAN-only mode - Close TermBeam when done — it's not a daemon, don't leave it running
- Use on trusted networks — TermBeam is not designed for hostile environments
Reporting Vulnerabilities¶
Please do NOT open a public GitHub issue for security vulnerabilities. Instead, report vulnerabilities privately via the Security Advisories page — click "Report a vulnerability" and provide a detailed description.
See Also¶
- Configuration — CLI flags, environment variables, and defaults
- Getting Started — install and run TermBeam in under a minute