Skip to content

Security & Permissions

The Mosayic extension is, by design, allowed to run shell commands on your machine. That’s not a side effect — it’s the whole job. So it’s worth being clear about what it can and cannot do, and what controls you have.

The extension protects against three things:

  1. A malicious dashboard. If someone took control of the Mosayic backend or hijacked your session, they could send commands to your extension. The per-command consent prompt (and the allowlist) is the brake.
  2. Eavesdropping. All communication uses HTTPS/WSS. The extension refuses to talk to plaintext HTTP for non-localhost URLs.
  3. Shell injection through command arguments. Commands sent from the backend are scanned for suspicious patterns (;, $(...), backticks, embedded newlines outside single-quoted strings) and refused if found.

It does not protect against:

  • A compromise of your Google account (whoever can log in to your Google account can sign in to Mosayic and command your machine)
  • A compromise of your local machine (anyone with shell access to your laptop can do anything; the extension can’t add protection beyond what your OS already provides)
  • A compromise of the CLIs you’ve signed in to (gh, gcloud, eas) — those have their own threat models

When connected, the backend can ask the extension to:

ActionWhat it can do
Run a one-shot shell commandExecute, capture stdout/stderr, return result. Subject to consent.
Open a VS Code terminal and run a commandVisible to you in the terminal panel. Subject to consent.
Start a managed dev serverStreams output to both your terminal and the dashboard.
Open a folder picker dialogYou choose what to share.
Open a folder as the workspaceLimited to the folder you (or the dashboard) specify.
Send keystrokes to a managed dev server’s stdinOnly to dev servers it started.

Every command runs in the first folder of your VS Code workspace (or your home directory if no folder is open). The extension cannot navigate outside your workspace folder unless the command itself does so (e.g. with cd).

  • Read files outside what a command run from your workspace folder could read
  • Make network connections beyond the WebSocket to the Mosayic backend (commands you run can, of course, do anything)
  • Modify your VS Code settings (settings flow the other way — you set them, the extension reads them)
  • Install other extensions
  • Trigger system-level events (logout, restart, etc.)

By default (mosayic.confirmCommands: "allowlisted"), the extension auto-approves commands that use known, well-scoped CLI tools and prompts you for anything else.

The allowlist is intentionally short and includes only tools that:

  • Are unambiguous about what they do
  • Don’t give arbitrary code execution (e.g. eval-like features)
  • Are needed by Mosayic’s normal flows

The current allowlist (as of extension v0.0.12):

gh, gcloud, expo, eas, supabase, npm, npx, node, nvm, docker,
mkdir, git, unzip, sed, jq, ssh-keygen, rm, mv, cd, printf, uv,
test, [, hostname, lsof, .

Anything else triggers a modal:

Mosayic wants to run: <command>

[Allow] [Allow All] [Deny]

If you want a tighter setting, change mosayic.confirmCommands to always. You’ll be prompted for every command, including the allowlisted ones.

Even for allowlisted commands, the extension scans the full command string for patterns that suggest shell metacharacter abuse:

  • ; outside of single-quoted strings
  • Command substitution: $(...) or backticks
  • Embedded newlines

Any of these refuses the command outright with an error sent back to the dashboard. This is to prevent a compromised backend from chaining gh auth status; rm -rf ~ or similar past the allowlist.

If you have a legitimate reason to run a complex command, run it in a terminal yourself.

Your access and refresh tokens live in VS Code’s secretStorage, which is backed by:

  • macOS — Keychain
  • Windows — Credential Manager
  • Linuxlibsecret (gnome-keyring or kwallet)

These are encrypted at rest by your OS and only accessible to processes running as your user.

The “Mosayic WebSocket” output channel is verbose for debugging. To avoid leaking secrets in logs, the extension redacts:

  • Bearer tokens (the value after Bearer )
  • Common secret-looking strings (password=..., token=..., api_key=...)
  • URLs with embedded credentials (https://user:pass@host)

This redaction is a defence in depth, not a guarantee. Don’t paste your output channel publicly without skimming it first.

If you set mosayic.environment: "custom" and point at an http:// URL that isn’t localhost or 127.0.0.1, the extension refuses to connect and shows an error. This avoids accidentally sending your bearer token over an unencrypted channel.

The exception for localhost is so you can run the backend locally during development.

Only one WebSocket per Mosayic user is allowed. If you sign in from a second machine, the first one is forcibly disconnected (close code 4001). This prevents an old, forgotten machine from continuing to receive commands.

The output channel keeps a record of every command the extension ran during the current VS Code session. After restart, the channel is cleared.

If you want a longer-lived record, you can copy the channel contents into a file periodically.

Please email security@mosayic.io rather than opening a public GitHub issue. We aim to respond within 48 hours.