Use GitHub's private vulnerability reporting: Security → Report a vulnerability. It is enabled on this repository, it is private until you and I agree to publish, and it gives us both a tracked thread rather than a mail I might miss.
If you cannot use it — no account, or you would rather not have one — open a public issue saying only that you have something private to report, with no detail, and I will come to you.
Please do not open a public issue for something exploitable until it has been fixed. For anything else — a spec ambiguity, a conformance disagreement, a question — a public issue is better, because other implementers benefit from reading it.
This is maintained by one person. There is no security team, no on-call rotation, and no service-level agreement. What you will get:
- An acknowledgement within a few days.
- An honest assessment, including "you are right and I do not have a fix yet".
- Credit in the changelog and the release notes, unless you prefer otherwise.
- No legal threats, ever, for reporting something in good faith.
What you will not get is a bounty. There is no money in this project.
Anything that breaks the protocol's central claim — that a holder of a ledger and the public keys can recompute the exact state offline, and detect any alteration:
- Forging, altering, reordering, truncating or omitting events in a way that still replays as valid.
- Two different ledgers that produce the same state hash, or one ledger that produces different hashes across conforming implementations.
- Any signature check that can be satisfied without the corresponding key.
- Canonicalisation differences that change a hash.
- Parser behaviour that admits malformed input as valid, in the kernel, the envelope reader, or the timestamp-token reader.
Spec defects count. The most serious issue found in this project so far
was not a code bug: the specification never required the genesis record to be
authenticated, so a forged or absent genesis signature replayed clean under
every scheme, and the root of every ledger was forgeable. That was fixed in
v2.0.0 — see MIGRATION.md.
It was found by someone implementing the spec from scratch and reading only
the document. If your reading of SPEC.md disagrees with what the reference
implementation does, that disagreement is a finding, whichever one turns
out to be wrong.
- The hosted service at api.satledger.org is a separate, proprietary product. Report issues there to the same address, but they are not SATROOT issues.
- Denial of service through resource exhaustion on inputs a caller controls and is expected to bound.
- Anything requiring the operator's private keys.
BOUNDARIES.mdandTHREAT_MODEL.mdstate plainly what an operator holding the signing keys can do; that is a documented limit, not a vulnerability.
The conformance corpus is the sharpest tool here — 68 vectors, 19 that must replay and 49 that must be rejected, with a standalone runner:
python vectors/run.py --impl your_verifier.pyAn implementation that accepts something in the reject set, or rejects something in the accept set, has found either a defect in your verifier or a defect in the specification. Both are worth reporting, and the corpus grew from 33 vectors to 68 because of exactly that exercise.
| Version | Status |
|---|---|
| 2.0.x | Supported. |
| 1.7.x and earlier | Unsupported, and known to accept an unauthenticated genesis record. Pin it only to keep verifying existing ledgers, never for new ones. |