Security and safety
What this actually proves
A proof that is described accurately is more useful than a proof that is described impressively. This page states the guarantee precisely, lists the ways an implementation can weaken it, and gives the safety rules for anyone creating or holding a Drop.
The guarantee, precisely
A confirmed, verified Drop proves exactly four things:
- These exact body bytes, this content type, this marker and this public key were committed together in a single Tapscript leaf.
- That leaf is a leaf the spent Taproot output committed to, before the spend existed.
- The declared SHA-256 equals the revealed body.
- The spend appears in a block on the chain the reading implementation follows, at or beyond its confirmation depth.
- Not authorship. The creator key is whoever signed the reveal. Anyone can commit to anyone's content.
- Not rights. Recording an image does not grant, transfer or evidence any right to it.
- Not value. The protocol has no opinion about what a record is worth.
- Not performance. A Pact with a
recordedenforcement floor proves its terms were committed, not that anyone honoured them. - Not agreement between implementations. Another indexer may read the same chain differently. Verify the implementation you rely on.
- Not availability of referenced content. If a body holds a pointer, Bitcoin proves the pointer and nothing about the thing pointed at.
Threat model for implementers
Every entry below is a real way to turn a sound protocol into an unsound product.
| Threat | Consequence | Mitigation |
|---|---|---|
| Recording a leaf without checking its Taproot commitment | Anyone can put any leaf in any witness. Records become forgeable at will. | Specification section 4 in full. Conformance C-B3 through C-B7. |
| Treating a verification exception as anything but a rejection | A malformed input that crashes the verifier is accepted by the error path. | Fail closed. Conformance C-B8. |
| Validating the creator key by length only | 32 arbitrary bytes are treated as a key. Downstream signature logic behaves unpredictably. | Curve-point validation. Vector IV-8. |
| Accepting non-minimal push encodings | Two distinct byte strings decode to the same fields, so a record has more than one serialization and content-addressing breaks. | Re-serialization equality. Conformance C-A2. |
| Accepting another protocol's marker | Two ledgers merge. A token event becomes an artifact and no result is reproducible. | Marker allowlist. Vector IV-2. |
| Rendering a body with its declared content type | An SVG or HTML body executes script in your origin, with access to whatever that origin holds. | Passive-content policy: inline only text/plain and raster images, everything else an opaque attachment, with nosniff and a restrictive CSP. |
| Trusting a body's declared type when storing or scanning it | The declared type is attacker-controlled. A body labelled text/plain may be anything. |
Treat the type as a claim; treat the bytes as hostile. |
| Serving a record without stating the confirmation depth or indexed height | A consumer cannot tell whether an absent record is absent or merely not yet scanned. | Publish network, depth and height. Conformance C-C10. |
| Patching a projection after a reorganisation | Custody drifts from immutable history and cannot be reproduced by a second implementation. | Roll back and rebuild. Conformance C-C8. |
| Guessing at an ambiguous reorganisation ancestor | An unreproducible history that no audit can confirm. | Stop with a named reason. Conformance C-C9. |
| Presenting a partial Pact outcome check as a full one | A user believes an outcome was verified when only its structure was checked. | State which of P-1 through P-9 were applied, every time. Conformance C-P4. |
| Presenting Pacts as having authority it does not have | Someone signs or sends funds on the strength of a reference-only surface. | Surface mode: reference and the enforcement floor. Conformance C-P5 and C-P6. |
Safety for people, not implementations
- No Drops or Pacts interface ever needs your seed phrase or private key. Any request for one is an attack, without exception.
- Review the body, the network, the destination and the fee before signing. A confirmed Bitcoin transaction is difficult to reverse.
- A wallet preview, a draft, or an unconfirmed transaction is not a record. For Drops artifacts there is no pending state at all.
- Rehearse on
signetorregtest. It costs nothing.
- If a screen says a Pact transaction is pending: do not sign, do not send funds. The reference service holds no funds and no live Pact state.
- Keep the full blueprint and the plan hash together. They are what let you prove later which document you agreed to.
- Verify any Bitcoin transaction independently, in a wallet or explorer you chose yourself.
- If two screens disagree, believe the chain. Fetch the record, fetch its body, and check the hash yourself with the decoder.
A note on content
Anyone can commit anything to Bitcoin, and a Drops indexer records what it finds. An implementation that serves bodies is publishing third-party content it did not choose and cannot remove from the chain. Serving decisions, including refusing to serve particular records, are a matter for the operator and the law that applies to them. The protocol has no removal mechanism, and adding one would not remove anything from Bitcoin.
Reporting a vulnerability
Report privately, not in a public issue. Use GitHub's private vulnerability reporting on the repository that holds the affected code.
| If the issue is in | Report at |
|---|---|
| This documentation: a rule stated wrongly, a vector that is wrong, a tool that reports a false result | drops-protocol-docs advisories |
| The OP_DROP carrier protocol or its documentation | op-drop advisories |
| A Bitcoin Universe product or service | The security policy on docs.bitcoinuniverse.io |
A useful report includes what you did, what you expected, what happened, and the smallest input that reproduces it. For a protocol-level finding, a test vector in the style of the test vectors page is the most useful thing you can send.
A byte string that this documentation says is invalid but the reference implementation accepts, or the reverse. A disagreement between the specification and the code is the most valuable bug either can have, and it is worth reporting even when neither behaviour is obviously dangerous.