Shellby
Security

Hands where you can see them.

Shellby gives an AI agent hands on your PC, so it's built to keep those hands where you can see them. Here's how, what it doesn't cover, and how to tell us when something's wrong.

Shellby with a question mark in a speech bubble: he asks before he acts

Found a security problem?

Please don't open a public issue. Use GitHub's private vulnerability reporting: the repository's Security tab → Report a vulnerability. You'll get a reply within a week.

Report a vulnerability
At a glance

Six promises.

Shellby never answers for you

In every mode except Autonomous, Claude Code enforces the permissions and waits for your answer. Shellby only relays it.

Going further needs a separate window

Anything that would mean fewer prompts, or answers from somewhere else, goes through an isolated confirmation window that even a compromised panel can't click.

Autonomous is never the default

It needs the confirmation window the first time, asks again once each time Shellby starts, and shows in red.

Every window is sandboxed

A strict CSP with no remote content and no inline scripts. Each window gets a fixed list of IPC calls, and the main process validates them and checks which window is calling.

Untrusted text is escaped or cleaned

Claude's replies are HTML-escaped, friends' crabs and plugin names are cleaned, and workflow values never become code.

Local data, no telemetry

History transcripts live in %APPDATA%\Shellby\sessions. The online features you can turn on are listed in the privacy policy.

Permissions

Claude Code enforces permissions; Shellby only relays your answers. In every mode except Autonomous, any action Claude Code would prompt for is sent to Shellby as a can_use_tool request and blocks until you answer. Shellby never answers on its own. Pending requests are denied if you stop the task or the panel session ends.

  • The panel answers; the confirmation window guards the rest. Anything that would go further (fewer prompts, or answers from somewhere else) goes through a separate, isolated confirmation window: its own sandboxed process and bridge, answers accepted only from that window, Cancel as the default, and one at a time (a stack of them is refused, not queued).
  • Autonomous mode (bypassPermissions) is never the default. Turning it on the first time needs the confirmation window, and switching into it asks again once each time Shellby starts.
  • ! commands (a message starting with ! runs in PowerShell, as you) are confirmed in the window the first time. PowerShell is started by its full path in System32, never by a name a project folder could shadow.
  • Self-built tooling is flagged. A permission card warns when a command runs a file Claude wrote in this conversation, and when a write or command touches Claude Code's own setup (skills, agents, commands, hooks, settings, CLAUDE.md, MCP config).
  • Subagent prompts go through the same gate, labelled with the helper that asked.

The app itself

  • Renderers are sandboxed. Every window runs with sandbox: true, contextIsolation: true and nodeIntegration: false, behind a strict CSP (default-src 'none', no inline scripts, no remote content). Navigation, new windows and browser permissions are refused. The crab's window, which draws friends' visiting crabs and stickers, has a bridge of its own that can only move him and take a file drop.
  • Model output is untrusted. Claude's replies go through a small Markdown renderer that HTML-escapes everything first and only emits a fixed set of tags. Links are inert until clicked, only https: links open, and hovering one shows where it really goes. File links never run, mount or install anything (scripts, executables, installers, disk images, macro documents are only shown in their folder), and are never opened on a network share.
  • Skins are data, not code. They're JSON, validated against a strict schema (hex colours only, bounded size), and drawn with DOM APIs.
  • Git copies don't run your repository's hooks. Bring home commits and merges Claude's work with git hooks turned off, because Claude can edit a tracked hook without a prompt in Auto-edit. Push is yours and runs your hooks as a terminal would.
  • Health checks read, and change only what you ask. Shellby runs only a fixed set of programs, with fixed arguments and no shell. End task asks in the confirmation window first, and Ask Shellby why uses fixed templates that tell Claude not to delete, kill or change anything.

Unattended work

Workflows and routines run unattended, with every step's permission mode fixed when you save it. Saving one that can act without asking (a command, a web request, a file write, or a Claude step in Smart, Auto-edit or Autonomous) shows the confirmation window, listing every command, prompt, address, header name, body and file in full, and asks again whenever any of them changes. A workflow Claude proposes is always confirmed and can't use Autonomous.

Outside data stays data

StepHow outside values get in
CommandEach {{ value }} is passed to PowerShell as an environment variable, never in the command's text.
ClaudeValues arrive inside «», with a line saying they're data, not instructions.
Web requestValues are encoded after the base address, and a value that changed the host is refused.
File pathA value that would leave its folder is refused.

Secrets are encrypted by Windows and never sent back to the panel, only allowed in commands and web requests (never in prompts, messages or files), reach commands through the environment, and are blanked out of everything a run records. At most 4 workflows run at once, and one that starts more than 60 times in an hour is paused.

Your credentials

  • Claude's sign-in is Claude Code's. Shellby never sees your Claude credentials. Always use my Claude plan (Settings → Claude) leaves out ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL and the Bedrock, Vertex and Foundry switches, so it always runs on your plan.
  • Your GitHub token, only if you let Claude use it. Shellby keeps its GitHub sign-in encrypted by Windows. If you turn on Let Claude tasks push code and open pull requests, that token goes into Claude Code's environment so gh, git and GitHub MCP servers work.

With Let Claude tasks push on, anything Claude runs can read your GitHub token. It is off unless you turn it on.

Online features

Phone notifications and tasks

Notifications go only to a destination you confirmed in the confirmation window. Answers from the phone use single-use codes, and prompts the card would warn about can only be answered at the desk. Starting tasks from your phone is off by default, Telegram and ntfy only, and the text only ever becomes the words of a prompt: lines starting with ! or / are refused, nothing from the phone can change the mode, model or settings, and every phone task runs in Ask first.

Visiting crabs

Off by default, and turned on only through the confirmation window, because it publishes a public gist. Friends' cards are untrusted: a card counts only if GitHub says the gist belongs to that friend, every field is cleaned to known keys and lengths, and item keys are only looked up in your own catalog, so a card can't carry pixels or markup.

Community packs

A shellby://install link carries only a pack id. Before anything installs, Shellby:

  1. looks the id up in the official registry index
  2. downloads only from the registry's own origin and path (redirects are checked too)
  3. enforces a size cap while streaming
  4. verifies the SHA-256 checksum from the index
  5. requires the pack's id to match the link, and validates it
  6. shows the isolated confirmation window listing every item

Skill Shop

Plugins are code, so the shop is treated like a permission prompt. Claude Code does the installing; Shellby only runs claude plugin subcommands with an argument array and no shell, accepts only plugin ids the CLI itself just listed, never passes -y, and shows the confirmation window naming where the plugin really comes from.

The plugin listener

While Claude Code everywhere is on, Shellby listens on 127.0.0.1:47913, never other interfaces. Every request must have an X-Shellby: 1 header, a JSON content type, a Host of 127.0.0.1 or localhost, and no Origin header. Browsers always send Origin on cross-site requests and can't add custom headers without a preflight Shellby never answers, so a web page can't reach it.

Hooks can change the crab's mood, count turns and XP, and send “he needs you” to your phone if you set that up. They can't start tasks, answer permissions or change files. The shellby command can start a task in any mode except Autonomous, with a token Shellby keeps in its own profile folder.

Threat model

The map behind all of the above: what's worth protecting, who might go after it, and where the trust boundaries are. The full threat model links each boundary to the code that holds it.

What's worth protecting

AssetWhy it matters
Your files and repositoriesClaude Code can read, edit and run things in them.
Your permission answersAn Allow that you didn't give is the same as giving Claude your keyboard.
Your Claude plan and billingShellby must never quietly move work onto an API key.
Tokens Shellby keepsGitHub sign-in, phone notification tokens, workflow secrets and the shellby CLI token.
Your machine's stateStartup apps, processes and Claude Code's own ~/.claude setup.

Who might attack it

ActorWhat they controlWhat they want
Model outputAnything Claude writes: replies, file contents, commands it proposesTo get rendered as code, to run without an Allow, or to change Claude's own setup for next time
A repository you openIts files, git config, hooks and CLAUDE.mdTo run a program when Shellby reads or merges it
Web pagesRequests from your browserTo reach the local plugin listener
Other people's contentFriends' calling cards, community packs, plugin marketplacesTo get pixels, markup or code onto your PC
Someone with your phone tokenYour Telegram bot or ntfy topicTo start tasks remotely
A compromised rendererOne window's JavaScriptTo reach IPC it shouldn't, or click its own confirmations

Trust boundaries

Out of scope: other programs already running as you, and Autonomous mode, which skips prompts by design. Changes that touch a trust boundary need a test and a note in the pull request.

Know the limits

What these protections don't cover:

  • Other programs running as you. Any program running as you on this PC can reach the plugin listener, as with any local port, and that includes reading the shellby command's token. The listener keeps out browsers and other machines, not your own programs.
  • Autonomous mode (bypassPermissions) skips the permission prompts. It's never the default and has to be confirmed in the confirmation window.
  • A GitHub token handed to Claude is readable by whatever Claude runs, if you turn on Let Claude tasks push.
  • Plugins you install are code, with whatever hooks and MCP servers they bring.

Shellby acts on your real files with your real permissions. Read what you approve, and keep backups.

Code signing policy

Releases will be signed with Azure Artifact Signing, under the maintainer's verified name.

Signing is being set up. Until the first signed release, releases are unsigned, and Windows SmartScreen may warn about them. Every release still lists SHA-256 checksums in SHA256SUMS.txt. How to check a download →

Only Shellby's own files are signed, and only when GitHub Actions builds them from a tagged commit in the repository (release workflow). The signing key stays in Microsoft's hardware and is never on a PC. Before publishing, the workflow checks that every exe is validly signed by the expected publisher. Before building, it checks that the publisher will match the last release's, so installed copies keep updating. How it works →

RoleWho
Committers and reviewersx-salmon. Pull requests from anyone else are reviewed before they're merged.
Release and signingx-salmon

Everyone in these roles uses two-factor authentication on GitHub and Azure.

Reviewing him? Start here.

The full security notes and threat model live with the code, and every boundary links to the file that holds it.