Security
Reporting a problem
Section titled “Reporting a problem”Please report security problems privately through GitHub: on this repository, open Security → Report a vulnerability. Do not open a public issue. Include what you found, how to reproduce it, and what an attacker gains.
What Pi Pocket protects, and what it does not
Section titled “What Pi Pocket protects, and what it does not”Pi Pocket runs a coding agent that executes commands on the machine it runs on, as the user who started it.
- Signing in. The owner’s sign-in link is the key to the server. Invites are one-time links that expire after 15 minutes, or an hour, a day, or a week when whoever makes one picks that; the longer one lasts, the longer a link that leaks can be used. Their codes are stored hashed. An owner invite, which only the owner can make, always lasts 15 minutes and gives the device that opens it the owner token itself, and with it full control; starting with
--rotate-tokensigns out every device that has it and ends owner invites not yet used. Tokens are random, stored hashed, and kept in anHttpOnlycookie. - Viewers can read, react, and chat. They cannot make Pi do anything.
- Anyone who can steer can do what you can. Through Pi, they reach your files, Pi Pocket’s settings and tokens, and its code. An invite to one session limits what someone sees in the app, not what Pi can reach. Neither do git worktrees or spend limits: a worktree keeps a session’s files apart, and a run is stopped only after the request that crosses its limit.
- Approvals. Lancet Guard approvals can come from anyone who can steer, including the person who asked, unless the owner turns on “Approvals need someone else” (Menu → Extensions); then, when nobody is known to have asked, only the owner can allow. A notification offers Allow only for a call that fits on one short line; anything longer opens the app first. A “Done when” check command runs after every answer without asking, so with Lancet Guard on it must be one the guard allows outright.
- The built-in browser reaches what this machine reaches:
localhost, your network, and the internet. Anyone who can steer can use it from the Browser panel, and Pi from itsbrowsertool; Lancet Guard does not check either, and pages can hold whatever they show. The addresses people open show in the session’s chat. Its pages run in Chromium on the server, not in your browser, so they cannot reach the app or its cookies. Only the owner opens files from the address bar or sees which servers run on the machine. If steering guests should not reach your network, turn Browser off in Menu → Extensions. - Models are a person’s to choose. Pi starts subagents only on their session’s model, or on models the owner allowed (Providers → Models for subagents); PiP passes a model only when its person named it; titles and summaries use the session’s own model. Subagents on another model, and PiP, ask a model’s sign-in afresh first and use none whose sign-in expired; a session’s own run, a subagent on its model, titles, and summaries just try the model, and a run that fails on an expired sign-in marks it. This guards spending against Pi’s choices, not against a person: anyone who can steer can pick a session’s model, and Pi, which runs commands, can reach Pi’s sign-ins and Pi Pocket’s files like anything else on the machine.
- Linked sessions (Agent Teams, off until the owner turns it on) widen what prompt injection can reach. A session that read something hostile (a page, a file, an issue) can pass it on to the other sessions of its team in a message, and a message makes Pi work in the target for the person Pi worked for in the sender, with that person’s access, in a session where other people may have written. Pi is told to take a linked session’s message as a request, not as an order from a person, and to do nothing destructive or with credentials only because one asks; that is guidance to the model, not a boundary. A message is fenced, and a team stops after 20 messages without a person, at the starting session’s spend limit, and at 10 sessions; a link gives no access to a session someone cannot already see.
- Plan mode keeps Pi to planning; it is not a boundary. Programs that people configured to run on their own, such as a git diff driver, run as they would for anyone.
- Drop-in extensions in
~/.pi-pocket/extensions/run inside the server with the owner’s rights. They stay off until the owner turns them on. One with a browser module also runs code in the app’s own page, with the rights of whoever’s tab loads it: the owner’s alone unless the module opens it to others (never to someone invited to one session). The page’s content security policy keeps that code from loading scripts and styles from another site or fetching from one, but code in the page could still send data out in other ways (navigating the page elsewhere, for one): turn on only browser modules you trust, as with the server part. What a module’s route throws withweb.errorreaches everyone who may use that route as it is; anything else it throws, only the owner reads. Every file of a web type (.js,.mjs,.css,.json, images, and.woff2fonts) in a browser module’s folder can be read by everyone the module is for. A module’s conversation command is offered to everyone who can steer that session, people invited to only that session included, and its handler runs with the owner’s rights: treat its arguments as untrusted, and check who runs it. A global command is the owner’s alone. - The extension gallery (Menu → Extensions → Find extensions) installs drop-ins other people wrote, so what it installs has the owner’s rights once turned on. It reads its index strictly, downloads only over https from each entry’s pinned commit, refuses a file whose SHA-256 differs from the entry’s, keeps file names inside the drop-in folder, and installs everything off; updates are never automatic. The index’s checks and its maintainers’ review lower the risk, but do not remove it: read the code (or ask Pi to review it) before you turn one on. Only the owner can use the gallery. A theme from the gallery is CSS, fonts, and images that the owner chooses to install. Pi Pocket checks it as every theme folder before it is in place, so it cannot load anything from other servers, nor the app’s own addresses, and it runs no code. It can still hide or relabel parts of the app, approvals too: install only themes you trust.
- Replies are untrusted. Anything Pi reads can steer what it writes, so the app page loads nothing from other sites, and replies cannot contain forms, scripts, or styling. Artifacts run in a sandbox with no access to the app. An HTML block in a reply is previewed in a frame of its own with its scripts off and a policy that loads nothing, not even from the app; tapping Run runs it as an artifact runs, with scripts and the network but no access to the app, so a page Pi was steered into writing could then send what it shows elsewhere. SVG blocks show as images, which run nothing.
Problems within these limits are bugs we want to hear about: for example, a viewer making Pi act, a session-scoped person seeing another session, or a reply reaching the app’s cookies or API.
These pages describe Pi Pocket 0.14.0. Your copy has the pages of its own version in its docs/ folder.