Security
June is a self-hosted orchestrator that spawns local CLI agents with broad filesystem access. This page is a level-set on what that means.
Trust boundaries
Section titled “Trust boundaries”| Boundary | Trusted? | Notes |
|---|---|---|
| The machine June runs on | Yes | June assumes you control the host. Don’t run on shared hosts. |
| The local runner CLI | Yes | The CLI executes with your local user’s permissions. |
| Linear webhooks | Verified | HMAC-checked against JUNE_LINEAR_WEBHOOK_SECRET. Mismatched signatures are dropped. |
| Linear API responses | Trusted | June assumes Linear is non-malicious. Don’t run against a Linear workspace you don’t trust. |
| Issue / comment content | Untrusted | Comments are user-controlled and feed straight into the runner’s prompt. Prompt-injection risk. |
Filesystem access
Section titled “Filesystem access”The runner inherits the user’s filesystem permissions. With Claude Code’s --permission-mode auto, it can read and write anywhere the user can — including files outside the project. There is no chroot, no per-issue jail.
OpenCode is the exception: June injects an OPENCODE_PERMISSION profile that denies external-directory access and arbitrary bash by default. Override with LINEAR_CLAUDE_OPENCODE_PERMISSION.
If you need stricter isolation, run the orchestrator in a container or VM with the working tree bind-mounted in.
Secrets
Section titled “Secrets”June reads secrets from environment variables only:
JUNE_LINEAR_API_KEY— Linear personal API key.JUNE_LINEAR_WEBHOOK_SECRET— Linear webhook signing secret.LINEAR_CLAUDE_ADMIN_TOKEN— bearer for/admin/*.
Never paste these into code, logs, Linear comments, or runner prompts. The orchestrator scrubs ANTHROPIC_API_KEY from the Claude child process so a stray env var doesn’t leak into the runner’s auth path — the runner uses its own login session instead.
Linear scope
Section titled “Linear scope”The personal API key has the scope you grant it. June only needs:
- Read on issues and comments (to fetch context).
- Write on issues (to transition state) and comments (to post replies).
Avoid keys with admin scope unless you specifically need it. If you only operate against one team, a key scoped to that team’s read/write is sufficient — set JUNE_LINEAR_TEAM_KEY so June ignores webhooks from other teams.
Webhook hygiene
Section titled “Webhook hygiene”Every incoming POST /webhook/linear is HMAC-verified against JUNE_LINEAR_WEBHOOK_SECRET before any DB write or routing decision. Mismatched or missing signatures are dropped with 401 Unauthorized. Dedupe runs on event id so a duplicated webhook delivery (Linear retries) does not re-trigger a session.
If you rotate the webhook secret in Linear, rotate JUNE_LINEAR_WEBHOOK_SECRET on the host and restart the service — old webhooks queued in flight will be dropped.
Admin endpoints
Section titled “Admin endpoints”/admin/* endpoints require Authorization: Bearer $LINEAR_CLAUDE_ADMIN_TOKEN. If the token isn’t set, the endpoints return 404 (not 401) to avoid advertising their existence. The endpoints are powerful — they can terminate runs and reconcile state — so do not expose them publicly without the token set and do not run June with an empty admin token on a public ingress.
Prompt injection
Section titled “Prompt injection”Comment bodies, issue descriptions, and image alt text all flow into the runner’s prompt. A Linear user with comment-write access can attempt to:
- Steer the agent to read or write files it shouldn’t.
- Steer the agent to make Linear API calls (via
linear-actiondirectives or by calling the API itself). - Steer the agent to install dependencies or run code.
June’s defense is shallow: it strips ANSI escapes, dedupes attachments, and constrains the linear-action action set. It does not pattern-match for injection attempts.
Mitigations:
- Restrict who can comment. Lock the Linear workspace to trusted members only.
- Run with the smallest filesystem footprint that works. Container, VM, dedicated host.
- Audit
linear-actionblocks. The orchestrator strips them from comment bodies and appends an execution summary, so they’re visible in the thread. - Watch logs.
logs/agent.logrecords every spawn, exit, state transition, and Linear API call.
Don’t run on shared hosts
Section titled “Don’t run on shared hosts”The runner CLI has the user’s full filesystem and network access. On a shared host (multi-user dev box, jump host, etc.), that’s a foot-gun. Run June on a single-tenant machine.
What June does not do
Section titled “What June does not do”- No outbound calls beyond Linear’s API and whatever the runner CLI initiates.
- No telemetry. No phone-home.
- No update channel. You pull from
mainand restart. - No multi-tenancy. One orchestrator, one Linear workspace, one user.
If any of those are a deal-breaker, June is the wrong tool.