Open a private advisory on this repository: Security → Report a vulnerability. It is visible only to the maintainer, and it is the right channel for anything you would not want in a public issue.
Expect a first reply within a week. If a report turns out to be real, the fix and the advisory are published together, and the advisory says what an installation had to be doing to be affected.
Public issues are fine for everything else, including a hardening idea that does not describe an exploitable path.
| Version | Supported |
|---|---|
newest 0.x minor |
yes |
| anything older | no |
There is no backport branch. A fix lands on main and goes out in the next release, which for a 0.x
project is the honest arrangement rather than a promise nobody could keep.
Three mechanisms, all of them declarations rather than runtime policy:
A capability is injected, never imported. An action receives exactly the capabilities its manifest
lists under requires. One that declares nothing is handed nothing, so it has no fetch, no shell
and no file access, and there is no ambient object it can reach for instead. The validators live in
lib/manifests.ts and are the only ones, so a manifest the checker accepts is one the runner accepts.
A declaration is also a placement constraint. shell cannot be satisfied by an edge isolate, so a
unit that asks for it is refused deployment there rather than failing at run time. The checker reports
this before a deploy, which is the point: the boundary is decided where you can still read it.
Secrets are filtered out of the record. Values resolved from the environment because a manifest
declared them are removed from every exit, including a failure exit, and redactAlso in
lib/execute.ts covers values the runner knows are credentials although no manifest named them. A
field listed under refuses is stripped before the action or the run record ever sees it.
This is not a sandbox, and it does not pretend to be one. The capability boundary constrains what
the runner hands an action. It does not constrain what a module can import for itself. Action code
runs in your process with your privileges, so an action you install can do anything the runtime can
do. Treat adding one exactly like adding a dependency, because that is what it is.
Deployed workers authenticate a bearer token, and nothing more. There is no user model, no scope and no per-caller rate limit. Anyone holding the token can invoke anything the worker exposes. Rotation, storage and blast radius are the operator's to own.
A run record holds envelopes. It is written so a run can be replayed and audited, which means it holds whatever flowed through the pipeline minus the declared secrets. If your envelopes carry personal data, the store carries it too, and it is the operator who decides where that database lives and how long it is kept.
The LLM seam sends your envelope to whatever provider you configured. Waybill neither inspects nor withholds what a step passes to it.