Report privately through GitHub's private vulnerability reporting on this repository: the Security tab, then Report a vulnerability. That channel is private to the maintainers and is the one to use — do not open a public issue for anything exploitable.
Include what you need to make it reproducible: the oam version
(oam --version), the platform, and a minimal script. If you have a working
proof of concept, send it — it shortens triage more than a description does.
You will get an acknowledgement within 3 working days. We aim to ship a fix or give you a dated plan within 30 days, and we will tell you before the fix goes public so the disclosure is not a surprise. If you want credit in the release notes, say so; if you want to stay anonymous, that is the default.
oam runs untrusted-ish JavaScript on a V8 isolate with a Node-compatible surface. In scope:
- Escaping the permission model (see below) — reading, writing, or dialling out when the corresponding permission is denied.
- Memory-safety failures reachable from JavaScript: a crash in the Rust or V8 layer that a script can trigger, and anything that looks like a read/write past a buffer.
- Module-resolution attacks: a specifier that loads a file outside the intended tree, lockfile handling that fetches something other than what was pinned.
- Anything in the release pipeline that would let a third party ship a binary users would accept as ours.
Not in scope:
- A script doing something destructive when run without
--permission. That is the documented default: oam without the permission flag has the same authority asnode, i.e. full access to the user's machine. - Denial of service by a script that is simply allowed to run — infinite
loops, deliberate memory exhaustion,
process.exit. - Node-compatibility divergences with no security consequence. Those are ordinary bugs; file them publicly.
oam --permission denies filesystem reads, filesystem writes, network
access, and environment access unless explicitly granted. The checks are
enforced in the native ops (crates/oam_engine/src/permissions.rs), not in
JavaScript, so monkey-patching fs does not route around them. A denial
throws Node's ERR_ACCESS_DENIED, carrying permission and resource.
Two things to be clear about, because the difference matters if you are relying on this:
- The default is no restriction. Without
--permission, every check returns granted. This matches Node, and it means the flag is opt-in hardening, not a sandbox that is on by default. - It is a permission model, not an isolate escape boundary. It gates the host operations oam exposes. It is not a defence against a V8 renderer exploit, and it does not make it safe to run genuinely hostile code. If you need that, run oam inside an OS-level sandbox as well.
oam embeds V8 via the v8 crate (currently 150.0.0; see Cargo.lock for
the exact pin of any given build). V8 security fixes reach oam when we bump
that crate and cut a release — we do not carry our own V8 patches.
If you are tracking a specific CVE, oam --version plus Cargo.lock from
the matching tag tells you exactly which V8 you have.
Every release publishes a SHA256SUMS file alongside the assets. Verify
your download against it:
sha256sum -c SHA256SUMS --ignore-missing
A checksum file served from the same place as the binaries protects against corruption and mirror tampering, not against someone who has compromised the release channel itself.
From v0.18.0 on, each release also carries RELEASE-MANIFEST (the tag plus
the SHA256SUMS lines) and RELEASE-MANIFEST.sig, an SSH signature made with
an offline-backed ed25519 release key. The signature is what proves
authenticity. Check the key fingerprints against this list, which is also
published in release-keys/README.md and the release notes:
| Key | Fingerprint |
|---|---|
oam-release-k1 (current) |
SHA256:zB7Aq4Ky/U90VJ4sAEp0e2A65KfQpiyQXJI4FuT2oss |
oam-release-k2 (next, offline) |
SHA256:Uy7nugF5mDzfM/8/fcUti9K+sQMbn/LdRAk+sIbWYs4 |
To verify a release by hand, see release-keys/README.md.
install.sh and install.ps1 check this for you, against copies of these keys
embedded in the scripts: a v0.18.0+ release installs only if its manifest
signature verifies, names the tag being installed, and comes from a key whose
range covers that tag. Releases before v0.18.0 are checked against a pinned
hash of their published SHA256SUMS. install/README.md has the details.
oam self-update makes the same checks with the keys compiled into oam.
The binaries are code-signed too, from v0.18.0 on:
- Windows: both
.exeassets carry an Authenticode signature from Azure Artifact Signing, publisher "Yaw Labs LLC" (a verified publisher). SmartScreen reputation for a new signature still builds up over time. - macOS: both binaries are signed with oam's own pinned, self-signed identity, "oam Code Signing (self-signed)", with the hardened runtime. That is not an Apple Developer ID signature and the binaries are not notarized, so Gatekeeper still blocks a quarantined (browser-downloaded) binary. curl and brew installs set no quarantine flag and are unaffected.
oam is in beta (pre-1.0), and it is used outside Yaw Labs. A security fix is disclosed in three places, once a release carrying it is out:
- The CHANGELOG, under that release's Security heading, states what was wrong and what changed.
- The GitHub Release notes summarise the release's security fixes first.
- A GitHub Security Advisory is published for each vulnerability, naming the affected versions and the release that fixes it. Where one of oam's security boundaries failed — the permission model, TLS certificate verification, TLS client authentication, or the client address a server reports — the advisory also carries a CVE ID, so scanners and vulnerability trackers see it.
Advisories describe the weakness and its impact, not how to exploit it. A reporter is told before a fix goes public (see above), and credited in the advisory and the release notes if they ask to be.
Fixes land on the latest release. There is no long-term-support branch — upgrade to pick up security fixes. An advisory names the first release that carries its fix; the release to run is the latest.