Security
Summary of the threat model. The authoritative copy with every numbered attack
scenario lives in
SECURITY.md.
Report channel
Email security@ochk.io. See
SECURITY.md
for the full reporting protocol.
What OC Stamp protects
- Authorship. Only the holder of
signer.address's private key could have producedsig.value. BIP-322 assumption. - Priority (confirmed anchors only). The envelope id existed on or before
the block at
ots.block_height. Bitcoin consensus assumption. - Integrity. Any tampering with
content.hash,content.length,content.mime,signer.address, orsigned_atinvalidatesidand thereforesig.value. - Stake (when declared and re-verified). At the moment a verifier resolves
stake.attestation_id, the holder ofsigner.addresscontrols UTXOs matching the declared bond.
What OC Stamp does NOT protect
- Recency.
signed_atis self-declared. Only OTS proves priority before a block, not absolute wall-clock time. - Uniqueness. A signer can sign the same content twice with different
signed_at. First-stamp ordering relies onots.block_height, notsigned_at. - Content liveness.
content.refcan 404 or mutate. The hash is authoritative; the pointer is a convenience. - Sender anonymity.
signer.addressis plaintext. For anonymity, sign from a fresh address — but you lose stake signal and identity continuity. - Post-quantum confidentiality / authenticity. secp256k1 and SHA-256 have finite lifetimes under sufficiently large quantum computers. No PQ layer in v1.
Assumptions
- Bitcoin's security model holds. secp256k1 / Schnorr remain unforgeable at current parameter sizes; work-weighted longest chain is canonical.
- BIP-322 is implemented correctly. Pin a verifier known to handle all address types (P2WPKH, P2TR, P2WSH, P2PKH).
- At least one OTS calendar is non-colluding. Submit to ≥2 independently-operated calendars.
- SHA-256 is collision-resistant. Practical collisions break
iduniqueness. - Randomness at signing time is strong for any ephemeral values used by the signing wallet.
Normative compliance requirements
A conformant implementation MUST:
- Reconstruct the canonical message from envelope fields before trusting
the declared
id. - Verify
sig.valueunder BIP-322 before trusting envelope contents. - Verify the OTS anchor against a real Bitcoin block header when
ots.status === "confirmed"and the caller attaches legal/economic weight. - Re-resolve any stake claim. Never trust the declared
sats_bonded/days_unspent— fetch the attestation. - Reject unknown
envelope.vvalues. Preserve unknown optional fields on relay. - Produce byte-identical canonical messages for identical inputs across implementations.
- Sign the hex form of
id(64 ASCII bytes) with BIP-322, not the raw 32 bytes.
Attack scenarios (selected)
The full list of 16 numbered scenarios lives in
SECURITY.md.
Highlights:
- Envelope tampering in transit — mitigated. Envelope id is
H(canonical), committed to bysig.value. - Signature replay across canonical messages — mitigated.
oc-stamp:v1domain separator prevents replay against other OrangeCheck protocols. - Fraudulent OTS proof claiming earlier block — mitigated. Verifiers walk proof to real Bitcoin header.
- Calendar–miner collusion to backdate — partially mitigated by using multiple independent calendars.
- Aggregator substitution — mitigated. Aggregator cannot sign; envelope is already signed when submitted.
- Pending proof used as priority evidence — mitigated by policy and the
E_NO_ANCHORerror. content.refreturns attacker-controlled bytes — mitigated. Verifiers fetching via ref MUST re-hash.- Key compromise of signer — accepted. Same trust model as BIP-322 everywhere. Rotate to a new address; past stamps remain valid via anchor.
Aggregator-specific risks
An aggregator (e.g., the reference service at stamp.ochk.io) is trusted for liveness only:
| Attack | Mitigation |
|---|---|
| Aggregator refuses service | Submit directly to calendars |
| Aggregator drops submission | Re-submit; OTS is idempotent |
| Aggregator delays pending proof | Re-query calendar directly |
| Aggregator returns fraudulent pending proof | Caught at upgrade; the "pending" proof cannot chain to any Bitcoin block |
| Aggregator strips / modifies fields | Invalidates id, fails signature verification on relay |
Dependency posture
Narrow surface:
| Package | Purpose |
|---|---|
@noble/hashes | SHA-256 |
@noble/curves | secp256k1 Schnorr / ECDSA |
javascript-opentimestamps (pluggable) | OTS proof parsing |
bip322-js | BIP-322 verification |
bip322-js transitively depends on elliptic, which has known low-severity
timing channels in ECDSA (npm advisory 1112030). Our use is verification-only
and signatures are bound to the BIP-322 message domain, so the risk is limited
to signature-check timing. A migration to a @noble-based BIP-322 verifier is
planned.