Jazz is an agent that executes real actions on your machine: it reads and writes files, runs shell commands, makes network requests, and drives external services. This document is both the vulnerability-reporting policy and the guide to running it safely.
Please do not open a public issue for security vulnerabilities.
Report privately via
GitHub Security Advisories. If you
cannot use that, email lvndry@proton.me with SECURITY in the subject.
Please include:
- What the issue is and why it matters
- Steps to reproduce, or a proof of concept
- The Jazz version (
jazz --version) and your platform - Any suggested fix, if you have one
You can expect an acknowledgement within a few days. We will keep you informed as we investigate, and credit you in the advisory unless you prefer otherwise.
Jazz is pre-1.0 and ships frequently. Fixes land on the latest published version — please
confirm the issue reproduces on the current release (jazz update) before reporting.
Some behavior that looks alarming is deliberate and documented rather than a vulnerability.
In scope — please report:
- A gated tool executing without approval, or any way to bypass the approval system
- Privilege escalation past the configured
--approval-policy/autoApprovetier - The command allowlist matching more than it should (e.g. a prefix-matching bypass)
- Credential or API-key leakage into logs, telemetry, transcripts, or error output
- Command or argument injection reachable from untrusted input
- Anything that lets a remote party act on a host running Jazz without local consent
Out of scope — working as documented:
--approval-policy high-risk(orautoApprove: true) permitting destructive commands. That tier exists to grant exactly that, and the docs say so.- A novel way to phrase a shell command that the denylist does not catch. The denylist is defense-in-depth against an accident, explicitly not a sandbox — approval is the real control.
- An agent acting on instructions embedded in content it fetched, when running at a tier that permits those actions. Prompt injection is real, which is why the tiers exist.
- Plaintext conversation transcripts under
~/.jazz/history/. Documented; treat that directory as sensitive. - An MCP server you configured doing something you did not expect. MCP servers are third-party code you chose to run.
If you are unsure which side of that line something falls on, report it — we would rather triage a non-issue than miss a real one.
Approval gating is the primary control. 15 of the built-in tools do not act when the model calls them; they describe what they would do (including a real diff for edits) and wait for approval — from you, or from the policy tier on an unattended run. Mechanism and risk tiers: Tools & approval.
A shell command denylist blocks 56 patterns before execution — privilege escalation
(sudo, su), filesystem destruction (rm -rf /), remote code execution (curl … | sh),
power/runlevel changes (shutdown), and reads of /etc/passwd, /etc/shadow, /etc/sudoers.
Quoting the implementation directly, because it matters:
This is a defense-in-depth denylist, not a sandbox. It cannot stop a determined attacker — variable expansion, base64 obfuscation, eval, and other indirection paths can route around any string matcher.
Its job is catching an accident from a confused model. Do not treat it as a boundary against
a hostile one. If you need a real boundary, use container isolation.
Implementation and the documented set of known bypasses:
shell-tools.ts,
shell-tools.security.test.ts.
Environment sanitization. Shell commands run with variables matching
API|KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH (case-insensitive), plus everything prefixed
SSH_, stripped from the environment. An agent's envAllowlist can exempt specific names when
a command genuinely needs one. Implementation:
env-utils.ts.
Local-only data. Credentials live in your config; telemetry is JSON on your disk and is
never transmitted. JAZZ_OFFLINE=1 stops Jazz initiating any outbound request of its own. See
Airgapped & self-hosted.
Audit trail. Every tool invocation is logged under ~/.jazz/logs/, with per-run token and
cost records under ~/.jazz/telemetry/.
This is the strongest control available, and it is stronger than any policy tier: an agent
whose toolset omits execute_command cannot run shell commands at all, regardless of
approval settings. Configure the toolset per agent rather than granting everything and relying
on the gate.
| Tier | Auto-approves |
|---|---|
unset / false |
Nothing |
read-only |
Reads, search, web requests, git status/log/diff |
low-risk |
+ manage_todos, spawn_subagent |
high-risk |
+ writes, deletes, shell, git commit/push |
low-risk is narrower than it sounds — it adds exactly two tools. Email, calendar, and
Obsidian are skills that shell out via execute_command (high-risk), so prefer allowlisting
one binary over raising the whole tier:
// ~/.jazz/config.json
{ "autoApprovedCommands": ["himalaya", "khal"] }Matching uses a parsed key (binary + first subcommand), never a raw prefix — git status does
not also permit git status && rm -rf /. Full tiers: Tools reference.
A chat bridge, a public webhook, or a CI job reviewing fork PRs takes input from someone who is
not you. At high-risk, a message — or a prompt injection inside a web page the agent fetched
— can run arbitrary commands on that host. Use an allowlist of senders, keep the tier low, and
trim the toolset. See
Chat platforms → security.
- Do I understand what this will do, and is it reversible?
- Am I in the right directory, and are the paths correct?
- For
git push— the right remote and branch?
For untrusted work or unattended deployments, isolate rather than trust:
FROM node:20-alpine
RUN npm install -g jazz-ai
USER node
WORKDIR /home/node
CMD ["jazz"]Also consider a dedicated OS user for running Jazz, and separate service accounts (a bot GitHub account, a separate mailbox) so a mistake cannot reach your primary identity.
- Stop the run — double-Escape interrupts generation and any running tool; otherwise exit the process.
- Check what happened —
~/.jazz/logs/has every tool invocation with its arguments. - Recover —
git reflogfinds the pre-mistake state, thengit reset --hard <commit>. For files, restore from backup or your trash. - Report it — if the cause was Jazz acting without approval rather than an approval you granted, that is in scope.
- Tools & approval — how gating and risk tiers are enforced
- Tools reference — every tool and its tier
- Configuration —
envAllowlist,autoApprovedCommands - Airgapped & self-hosted — removing outbound network entirely
- Security questions: Discord · Discussions