Report privately through GitHub Security Advisories. Please do not open a public issue for a security problem.
Include what you did, what happened, and what you expected. A proof of concept helps but is not required. This is a one-person project, so expect a first reply within about a week rather than within hours.
Only the latest tagged release is supported. There are no backports.
Janus is a desktop application that runs a coding agent against your own repositories. Understanding its actual privileges matters more than any promise this file could make.
- It edits your repository directly. Janus works in the repository you select, on whatever branch it is currently on. There is no scratch copy and no separate branch. Git is the only undo mechanism, and it does not cover uncommitted or untracked work.
- It runs shell commands. With the local model, each
run_bashcall requires your approval by default. Approval is remembered per workspace once you grant it. Claude Code goes through the same gate; Codex does not — its shell runs without a per-command prompt. - It spawns subprocesses — the model server,
uv,git, PTY shells, and (when selected) theclaudeorcodexCLI you already have installed. - It serves a local HTTP and WebSocket API on
127.0.0.1:8765, authenticated with a token minted fresh on each app launch and handed only to the app window. Requests are also Origin-checked. - It stores data locally — SQLite under the app's user-data directory. Your repository and its Git history are never copied into it.
- Path jail. File tools resolve every path against the workspace root,
follow symlinks, and refuse anything outside it. Subscription CLIs are confined
by
--restricted(Claude Code) or the sandbox mode (Codex). - Default-deny tool approval.
write_file,edit_file,run_bash, andhttp_getrequire approval on the local path. A missing or failing approval callback is treated as a refusal, and no response within 300 seconds is a refusal. - Tool scoping. An AgentProfile grants a specific tool set. Subscription CLIs receive exactly that set — if the profile withholds shell, the CLI has no shell tool at all.
- Per-action approval on Claude Code. The CLI's own write/edit/shell tools are withheld and Janus serves its own over MCP on a per-session URL, so a mutation cannot happen without the approval callback returning true. There is no built-in tool left to route around it.
- Review and ship gates. Committing through the ship flow requires an accepted review at the current revision with all verification runs passing. Pushing requires a Janus-recorded commit matching HEAD and an explicit SHA confirmation.
- Skill imports are inert data. Imported
SKILL.mdtrees are compiled, never executed; embedded scripts and hooks do not run.
Stated plainly, because assuming otherwise is how people get hurt:
run_bashis not path-jailed. Only its working directory is set. A command cancdanywhere the user can. Approval is the only barrier, and the subscription path has no approval.- There is no OS-level sandbox. The agent runs with your user's privileges. Janus's jail is application-level, not a security boundary against deliberate escape.
- Codex does not ask before each action. Its scope is enforced; individual writes and commands are not. Claude Code is gated — its write, edit, shell and fetch tools are removed and replaced with Janus's own over MCP, so every one of them reaches the same approval prompt the local model uses.
- Tasks are not isolated from each other. Two Tasks in the same project share one working tree, so each sees the other's uncommitted edits and commits onto the same branch. Janus refuses to run two of them at once, but it does not undo what an earlier Task left behind.
PUT /tasks/{id}/development/filewrites into the workspace with no approval, lease, or budget. It is the human editor's path and is intended, but it is another door into the same directory.- The workspace file jail is not a multi-tenant boundary. Janus assumes a single trusted local user.
Point Janus at repositories you can afford to have modified, commit or stash before delegating, and read the diff before you ship. If you are evaluating it, use a scratch branch.