Errand is under pre-release v0 development. Security fixes target the current
main branch. Older commits and development snapshots are not separately
supported unless the issue also affects current main.
Please report vulnerabilities privately through GitHub private vulnerability reporting. Do not open a public issue for an undisclosed vulnerability.
Include the affected revision, required access, realistic impact, and the smallest reproduction you can provide. Please avoid including real credentials, tokens, or unrelated private data.
Errand runs jobs only on explicitly selected or configured machines. Its
read-only discovery command may probe candidate runners returned by the
caller's own tailscaled node list. Tailnet requests authenticate through
Tailscale identity and are authorized by application capabilities or a
runner-local allow_users list, subject to overriding deny_users entries.
SSH requests authenticate through SSH and
bridge to a private Unix socket; the daemon grants local requests only when
kernel peer credentials match its OS user. Jobs run directly as the runner's OS
user, transfer workspace snapshots, and can return selected workspace changes
to the originating client.
This policy covers the CLI, daemon, HTTP protocol, authorization, snapshots, archives, caches, receipts, retained changes, local change application, process cleanup, attached TCP forwarding, configuration and profiles, local access management, diagnostics, and release packaging and publication workflows. The product and configuration contracts are in docs/DESIGN.md and docs/CONFIGURATION.md.
The following properties must hold:
- Requests fail closed unless the caller has the required Errand action.
- An active exact
deny_userslogin match overrides tailnet capabilities andallow_users. Saved access edits take effect only after daemon restart; tailnet login denials do not revoke SSH or Unix-socket access, deny tagged nodes without that login, or terminate existing jobs and streams. - Job status, logs, changes, signals, forwarding, and collection respect the authenticated ownership boundary.
- Job identifiers, manifests, archives, cache addresses, and change bundles cannot escape their intended state, workspace, staging, or destination roots.
- Archive extraction validates paths, types, symlink targets, declared hashes, and size limits before trusting transferred content.
- Retained changes are verified and applied only through the explicit, conflict-safe application path. They cannot silently widen their destination.
- No initiator environment value or credential is forwarded implicitly. Jobs
receive a small runner-side allowlist (
PATH,HOME,USER,LOGNAME,LANG, andTMPDIR) plus values explicitly declared by the caller. Receipt metadata does not retain the declared values. Ambient variable forwarding requires personal configuration, an explicitly selected profile, or CLI--passenv; nonempty top-level workspaceenv.passis rejected. Configuration and doctor diagnostics expose names and provenance, not values. - Workspace defaults and explicitly selected profiles may choose personally configured peer aliases, apply preferences, and session forwards. They cannot define peer transports or bypass snapshot-boundary protections. Profiles are never selected automatically; attachment profiles cannot retarget a job or apply run environment, workdir, or apply preferences to it.
- Retries cannot execute an admitted job twice. Ambiguous state is reported and is never treated as permission to replay execution.
- Attached TCP forwarding requires the appropriate action and ownership of a running job, and creates only client-local loopback listeners.
- Peer discovery probes only online nodes returned by the caller's own tailnet at the fixed Errand port. It must not scan arbitrary hosts or write client configuration.
Report authentication or authorization bypasses, cross-owner access or control, unexpected command execution without an equivalent execution grant, secret disclosure, replay of an admitted job, unsafe archive or path handling, writes outside protected roots, unsafe local change application, or bypasses of documented resource and forwarding boundaries.
Assess severity from realistic reachability and additional authority gained. Unauthenticated execution, cross-owner access, credential disclosure, or writes outside a protected client or runner boundary are high-impact findings.
- A
submitgrant intentionally provides shell-equivalent authority as the runner's job OS user. The caller chooses the executable and argv. Direct execution of those values is expected behavior, not command injection. - Host jobs run trusted code and are not isolated from the runner account. Errand is not a containment boundary for hostile workloads.
- For host jobs, forwarding's job check is an ownership and liveness gate, not a network-isolation boundary. The tunnel can reach any service listening on the runner's shared IPv4 or IPv6 loopback at the selected port.
- In v0, jobs and daemon state share an OS user. Receipts are diagnostic and append-only as emitted by Errand, but are not tamper-evident against a local administrator or a hostile job with the same OS authority.
- Resource consumption inherent in an authorized arbitrary command is not independently reportable unless it bypasses an Errand-enforced limit or crosses another caller's boundary.
errand serve --insecure-no-authis an explicitly dangerous, test-only mode. A finding that requires this flag alone is outside the supported security model. Secure operation must remain fail-closed when the flag is absent.