Share a Terminal Session Password With a Teammate Without the Service Seeing It: shell.online v0.23.1 Password Requests

Share a Terminal Session Password With a Teammate Without the Service Seeing It: shell.online v0.23.1 Password Requests

GitHub shipped local sandboxing for the Copilot app today. The changelog puts the point in one sentence: it "helps reduce the potential impact of unintended commands by limiting access to files, network resources, and credentials on your machine." The day before, OpenAI rolled GPT-6 Sol and Luna into Codex and the API at half the price of the 5.6 series. Both circle the same problem. Coding agents now run long enough, and cheaply enough, that other people need to look at them, and the moment a second person opens a session the question becomes who holds the credential. shell.online v0.23.1, released today, adds a way to share a terminal session password with a teammate where the service in the middle never gets a copy it can open.

Where the password lives before anyone asks for it

Start a session with the CLI and it prints a link, a password and a QR code:

shell --name "GPT-6 migration" codex

The process stays on your machine. The link and the password together are the access credential: anyone holding both can open the terminal and, unless the session was started with --read-only, type into it with the permissions of the wrapped process. The security model page says to treat the QR code the same way, since it carries the password for one-scan access. The relay in between forwards ciphertext. The browser derives the key from the password and the salt in the URL fragment and decrypts locally, which is why the password is a real secret and not a convenience.

That is the whole model without an account. Nothing in this post changes it. What v0.23.1 changes is what happens when you have linked the machine with shell auth, joined an organization, and a colleague opens the session from the app without having been handed the password.

What a teammate sees, and what the owner does

Inside an organization, everyone sees every member's sessions in the app. A session this browser has no password for shows a small lock beside its name. Open it and the unlock prompt offers the usual choices, vault or session password, plus a button labelled "Ask owner for the password". The asker's pane then reads "Asked owner for the password. This opens by itself when they accept."

The owner gets a blue count on the Share button, a "Password requests" item in the Share menu, and a Password requests section on the session page with Accept and Decline for each pending request and the last ten answers. Accepting takes one click. On the asker's side, the next poll brings the sealed copy and the terminal opens without them typing anything. A declined request shows "Ask again". The whole exchange is recorded in the team's audit trail as a handoff entry.

That description comes from the UI components in the shell.online repository, specifically the terminal pane's gate and the PasswordRequests component under app/src. The changelog lists the feature under v0.23.1.

Why the service cannot read the password it relays

The interesting part is the accept path. The accounts service holds no copy of any session password it can open. Every password it stores is sealed to an account's vault public key using ephemeral ECDH P-256, HKDF-SHA256 and AES-256-GCM, bound to the session ID and the recipient. The matching private key sits encrypted under a random vault key, and that vault key is wrapped only by a recovery key the service never receives. So when the owner clicks Accept, their own browser does the work: it unlocks their vault, reads the session password, seals a fresh copy to the asker's vault key, and sends that sealed blob along with the approval. The server writes the sealed copy and the answer in one transaction, so a request can never read as approved without the password having gone with it. The migration comment in the repo says it plainly: "The service never holds a password it can open, so it keeps only the ask."

A few rules fall out of the server route directly:

  • Only the session's owner can answer. Organization admins and assignees cannot, because neither owns the machine the session runs on.
  • One answer per request. A second answer is refused, and asking again after a decline creates a new request.
  • Asking requires a vault. Without one there is nowhere for the owner to seal the copy, and the request is rejected before it is stored.
  • The owner sees who asked. Other members see only their own request.

There is one trust decision the browser makes rather than the math. If a teammate's vault key has changed since the owner last sealed something to them, the owner is asked to confirm before anything is sealed to the new key. That is either a colleague who reset their vault or a key that is not theirs, and the app treats the first key it sees for a person as trust-on-first-use. The security policy in the repo is explicit that the hosted web app is trusted while it is open, since it performs the unlock and the sealing; the vault protects stored data and database copies, not against malicious JavaScript served during that unlock.

Share a terminal session password without the service seeing it: the edge cases

A password request is a way to grant terminal access, so the same consequences apply as when you paste the password into a chat. The teammate who receives it can type into the process. If they only need to watch, the owner should have started the session read-only in the first place, since --read-only rejects both browser and MCP input and a request-granted password does not change that. If access needs to end, the owner runs:

shell password rotate <ID>

Rotation changes the password, salt and cipher generation, disconnects current viewers, revokes MCP grants and replaces the sealed copies from the previous generation in the account registry. It cannot erase output a viewer already received. The CLI reference on shell.online lists the exact behaviour of each subcommand.

Network loss on the host does not affect any of this, because the request and answer live in the accounts service, not the relay. The host reconnecting after a dropped connection keeps the same session and the same password, and a copy already sealed to the teammate still opens it. The requests table is keyed to the session row and deleted with it, so nothing about a request outlives the session record.

Signing out locks the vault in that browser, which means an approved copy stays sealed until the teammate unlocks again. That is why the approved-state message says to unlock the vault if the pane does not open in a moment. And v0.23.1 also tightened the local side of the same story: looking up sessions no longer deletes a live host's control socket or saved credentials after a denied or slow probe, and a persistent launch reserves local control before it resumes the relay so a second launch cannot overwrite the first one's credentials. Those fixes matter most for long-running sessions, which are the ones people ask each other for.

Linking a machine is optional and the CLI works identically without it. What the account learns is the share URL, command name, host name and timing. It never receives terminal contents or the browser password. A password request, like the existing share action, moves a password between colleagues only as a copy sealed in the owner's browser to the recipient's vault key.

Why this is the right week for it

GitHub's sandboxing entry is careful to note that the local policy does not apply to cloud sandbox sessions or sessions running on a remote host, and that if the operating system cannot enforce the requested policy, "the sandboxed shell fails with an error rather than running without a sandbox." That is the right default, and it is the same instinct behind refusing a password request when there is no vault to seal to. Tools are converging on the position that a middle layer which cannot enforce a boundary should say so rather than pretend.

The GPT-6 rollout makes the volume side concrete. OpenAI says GPT-6 Sol is aimed at complex tasks like coding and makes about half as many mistakes as its predecessor, and TechCrunch reports the new versions are available in Codex for most paid accounts. Cheaper, more reliable agents mean more sessions running unattended, which is the case the original browser-link write-up was built around. A phone view of a running Codex session is only useful to a teammate if they can get in, and getting in should not require the owner to paste a secret into Slack.

This is also the pattern we care about at Pilot Protocol, where the overlay network exists so agents can reach each other over encrypted tunnels without a central party reading the traffic. A password request is the small, human-scale version of that: the coordination goes through the service, the secret does not.

Give a teammate the session, not the machine

Start any agent or command with one line, link the machine if you want the app, and let colleagues ask for access instead of chasing you for a password.

Try shell.online
About this article

Published by the Pilot Protocol team. Product claims are scoped to the availability labels and technical references linked in the article; deployment behavior can vary by version and environment.

How we publish · Suggest a correction · Technical references