Security

How Terminalwire safeguards workstation resources with entitlements

Terminalwire makes it easier for web developers to build commmand-line applications for their web apps. It accomplishes this by streaming command-line I/O between a web server and client over WebSockets.

Terminalwire Client

The Terminalwire client is a thin-client that users install on their workstation. It sends and recieves commands to and from the server to accomplish various command-line tasks like printing text to screen, launching a URL in the browser, or reading and writing files.

Terminalwire Server

The Terminalwire Client connects to a Terminalwire Server over WebSockets. Once connected, the server is capable of issueing commands to the client to perform various tasks including reading and writing files, launching URLs in the browser, and printing text to the screen.

Authority

Terminalwire uses URL authorities to secure client workstations between different domains. This is similar to the way browsers secure cookies between different domains.

URL authorities are the domain name and non-standard port. For example, the URL https://example.com would resolve the authority example.com. The URL https://example.com:3000 would resolve the authority example.com:3000.

Initialization

When the client connects to the server, it sends initialization message to establish and negotiate a connection. The client includes information about the opearating system version, Terminalwire client version, and protocol version to help the server determine how to best communicate with the client.

The server responds with a ready message to indicate that the client is ready to receive commands.

Entitlements

By default the server can reach almost nothing on your workstation. It gets stdin, stdout, and stderr, and it gets the per-origin storage path (~/.terminalwire/authorities/$ORIGIN/storage), where it keeps your session cookie and other config for that server. Everything else—reading an environment variable, opening a browser URL to another host, reading or writing a file outside its storage—is denied until you grant it.

Grants are scoped to the origin (scheme://host:port), the same way a browser scopes cookies and permissions. A grant you give wss://example.com never applies to wss://other.com, and ws:// (plaintext, for local development) is a separate origin from wss://, so you can’t grant a plaintext server by accident.

When the server asks for something it isn’t allowed, the client denies it and prints exactly how to allow it:

terminalwire: denied read of env SECRET
  allow it with: terminalwire-exec policy example.com env SECRET --approve

Granting access

Grants live in a per-origin YAML policy file that you own. Edit it with terminalwire-exec policy—which runs out of band from any session, so a server can never grant itself access—by hand in $EDITOR, or with a tool like yq.

List the origins that have a policy
terminalwire-exec policy
Show one origin's policy
terminalwire-exec policy example.com
Print the policy file path, e.g. to edit it directly
terminalwire-exec policy example.com --path

Approve, deny, or revoke a specific resource. --approve allows it, --deny blocks it even where a default would have allowed it, and --revoke removes the rule:

Let the server read the SECRET environment variable
terminalwire-exec policy example.com env SECRET --approve
Let it open another scheme, or a browser URL to another host
terminalwire-exec policy example.com scheme ftp --approve
terminalwire-exec policy example.com host docs.example.com --approve
Let it read and write files matching a glob (mode: ro, rw, or an octal like 0644)
terminalwire-exec policy example.com path '~/projects/**' rw --approve
Block or remove a rule
terminalwire-exec policy example.com env SECRET --deny
terminalwire-exec policy example.com env SECRET --revoke

A bare hostname defaults to the wss:// origin; pass a full scheme://host:port to target another, such as ws://127.0.0.1:8744 for a local development server.

Terminalwire.com entitlements

The terminalwire.com is granted elevated entitlements by the client so it can perform installation, troubleshooting, and other administrative tasks on the client workstation. These entitlements are detailed in the Resources section below.

Resources

After the client sends the initialization message, the server then requests the following resources from the client:

  • stdin: The standard input stream for the client.
  • stdout: The standard output stream for the client.
  • stderr: The standard error stream for the client.
  • exit: The exit status of the client.
  • browser: Launch a URL on the users workstation.
  • file: The configuration file on the client used to store API credentails, session cookies, and other local configuration data for the endpoint.
  • directory: Create, read, update, and check for existence of directories on client.

The client responds with messages on whether or not the resources are available. When all the devices are ready, the client & server can begin streaming commands between the resources.

Standard I/O

The stdin, stdout, and stdin resources are part of the standard I/O streams. The client grants the server permission to read and write to these streams by default.

Files

Terminalwire uses the files device to store API credentials, session cookies, and other local configuration data for the endpoint. These entitlements are implicitly granted by the client.

Files requires an entitlement to read and/or write files to a path on the client. The client must grant the server permission to read and/or write files to a path on the client with the exception of the ~/.terminalwire/authorities/$AUTHORITY/storage path, which is used to store API credentials, session cookies, and other local configuration data for the endpoint.

The terminalwire.com authority has an entitlement to the ~/.terminalwire/bin/** path by default to manage the installation, listing, and removal of Terminalwire apps.

Directories

API credentials, session cookies, and other local configuration data for the endpoint are stored in the files device on the client.

The terminalwire.com authority has an entitlement to the ~/.terminalwire/bin/** path by default to manage the installation, listing, and removal of Terminalwire apps. It also has an entitlement to shell initialization files in the ~ directory to aid users in appending the $PATH variable to their shell initialization file.

Environment Variables

The client’s environment variables are not shared with the server by default, with the exception of the TERMINALWIRE_HOME path. This path is necessary to store API credentials, session cookies, and other local configuration data for the endpoint.

The client must grant the server permission to read and/or write environment variables.

The terminalwire.com authority has an entitlement to the PATH variable to manage the installation, listing, and removal of Terminalwire apps.

Browser

The Terminalwire server can launch URLs in your browser. By default the client only allows http and https URLs to the same host as the server—so a server at example.com can open https://example.com/... but not another site. To allow another host or scheme, grant it:

terminalwire-exec policy example.com host docs.example.com --approve
terminalwire-exec policy example.com scheme ftp --approve