Security
VESPR lets people and AI agents change files and run commands in a shared workspace, so who may do what matters. This page lists what is protected today and, just as clearly, what is not.
On this page
Where we stand
VESPR is a prototype. No outside company has audited it. There has been no penetration test, no SOC 2 report and no bug bounty program. The checks listed below are ones we built and tested ourselves.
The trust model in one paragraph
A workspace is a team. Anyone with a valid access token for a server can join any workspace on it, read it, edit it, read its session log and its git repository, and approve what an agent wants to do. There are no per-workspace or per-person permissions yet. Agents are separate identities, and they are not trusted to act alone: what they may do without asking is set by the workspace’s permission mode.
What is implemented today Implemented
| Control | What it does | Where to check |
|---|---|---|
| Workspaces need a token | Every connection and every API call (live sync, uploads, session log, git, suggestions, runners) needs a valid token. No token, no access. | server/index.js, git.js, uploads.js, runners.js |
| Uploads are downloads only | Uploaded files get a random name on disk and are always sent as an attachment with a neutral type, so an uploaded web page or SVG can never run on our site. Nothing uploaded is executed or unpacked by the server. Size, count and per-workspace caps apply. | server/uploads.js |
| The room approves agent actions | Five permission modes. In the modes that ask, an Approve / Deny card goes to everyone and the first answer decides, with the name of who answered. Dangerous commands (for example sudo or rm -rf /) are refused outright. Bypass is downgraded to Auto on someone else’s machine. An agent also asks before editing a file someone is working in, in every mode. | agents/src/policy.js, agent.js |
| Run limits | A runner never inherits your environment variables, runs only workspaces its owner allowed, works in a temporary folder with time and output limits, and never writes outside it. Only agent identities can start jobs on runners, so a person cannot skip the approval flow. The public demo also caps memory, processes, CPU and AI tokens per day. | runner/lib.js, server/index.js, deploy/judge/ |
| Git pushes are filtered | A push cannot bring in .git or .vscode paths, paths that climb out of the workspace, absolute paths, more than 2,000 files or files over 200 KB. Only one git operation per workspace runs at a time. | server/git.js |
| Other people’s text is escaped | Names, model names, messages and colors sent by other clients are escaped or validated before they reach the editor’s HTML or Markdown. | the editor extension in extensions/ |
| Request size limits | Inline suggestions, runner jobs and git pushes have size limits so one request cannot flood the server. | server/*.js |
| HTTPS and link hygiene on the demo | The public demo is served over HTTPS. The app page sends no referrer and blocks content-type sniffing. The access token goes in the part of the link after #, which browsers do not send to a server. | deploy/judge/Caddyfile |
| Secret scanning before commits | A pre-commit hook blocks any commit that contains a real key, token or password. The same scan gates the public copy of the code and the demo’s deploy bundle. Secrets live in files outside the repository that git does not track. This protects our own code and keys; it does not scan your workspace. | scripts/check-secrets.py |
What is not in place Not in place
These are known, and we would rather you read them here than discover them.
Anyone with a token can reach everything on that server
A valid token opens every workspace on the server: files, chat, session log, git and uploads. Anyone in a workspace can approve any agent action and change the agent’s mode. Roles (owner, editor, viewer) are the planned next step.
Per-file read limits cannot be enforced inside one workspace
A workspace is one shared document, and every editor that connects receives all of it. We cannot let a teammate read some files and not others inside it: a limit like that would be a menu setting, not a protection. If two people must not see the same file, they need separate workspaces. Roles would help with who may change or approve things; a real per-file read limit needs a different design, and that is not built.
The agent’s sandbox is not isolated from the agent’s own secrets
When someone approves a command, it runs in a sandbox as the same system user, in the same container, as the agent that asked for it. Starting the command with a cleaned environment does not change that. A command run there can read what the agent itself can read: the agent’s model key and its workspace token, and the list of access tokens the agent is given. A workspace member can already get to these by asking the agent to run a script and approving it. Until this is fixed, the Run button for people is off by default on public deployments. The real fix is a separate sandbox container with no secrets, or running commands as a different user. That is not done yet. The sandbox also shares its container’s network, so a command can reach the internet.
Tokens are basic
Workspace tokens sit in a plain file on the server (outside the code repository), not hashed. They are compared with an ordinary lookup, not a constant-time one, and for live-sync connections they travel in the web address, which the server does not log but anything in between might. A preview link made by “Run it” carries its own secret in the address; anyone who has the link can see that preview. Tokens are issued and removed by the operator by hand.
The session log keeps everything
It records everything typed in a workspace, including anything sensitive someone pastes. Nothing is redacted and nothing is deleted automatically.
Smaller known limits
- Uploads for every workspace are readable with any valid token on that server.
- Someone who registers a runner can give it a misleading machine name (the interface also shows the owner’s name beside it).
- The VS Code workspace-trust prompt cannot be accepted ahead of time in the browser build, so a one-time prompt appears.
- The secret-scan hook can be skipped by someone who is determined to skip it; only a team rule stops that. Other repositories we maintain do not have the hook yet, and the wider scan is run by hand.
- We have not set up encryption of workspace data beyond what the hosting provider’s disks give us, and we have not documented a backup process. [to confirm before publishing]
Accounts In development
An accounts system exists in the code, off by default and not part of the public demo. As written it hashes passwords with scrypt and a per-user salt; stores only a SHA-256 hash of each session token (valid 30 days); counts failed sign-ins and blocks after five in 15 minutes; supports authenticator-app codes and single-use recovery codes (stored hashed); and can restrict sign-up to listed email domains. Known weak spot: authenticator secrets and phone numbers are saved in the account file without separate encryption (the file can only be read by the server). It has not been independently reviewed and will not be turned on for the public until it has been tested more.
Reporting a problem
Write to [Security contact email] with what you found, how to reproduce it and what you think it exposes. We aim to reply within [number of days]. We have no bug bounty. Please do not read other people’s workspaces, do not run tests that could take the demo down, and give us a reasonable time to fix a problem before you publish it. [lawyer to review any safe-harbor wording]