# Security policy ## Reporting a vulnerability Please report vulnerabilities privately, not in public issues: - Send an e-mail to the maintainers at info@activething.com with "DateKeys security" in the subject. Ask for an encrypted channel before sending sensitive material. - Do not open an issue on the repository for a vulnerability. Include a reproducible case: ideally a `.dkc` or `.dkk` file, or a test in the style of `capsule/mutation_test.go`. We aim to acknowledge reports within three working days. ## Supported versions The module is pre-1.0 (`v0.x`). Only the latest `v0.x` release receives fixes. ## Scope and assumptions In scope: every rule of the DateKeys Protocol Specification v0.11, tagged `spec-v0.11`, and of the draft v0.12 of the branch `v0.12`, that this module implements (see `docs/traceability.md`), the CLI, and the handling of untrusted input (`.dkc`, `.dkk`, relay responses, author key files). Among it: the paths and texts of a format 3 head, which the CLI writes to disk and to a terminal; the signatures, certificates and seals of the security area, whose names reach the lines of the verdicts; the public note; and the locator of a `.dkk`, with its addresses. The protocol's own limits, which are not vulnerabilities of this module: - The Quicknet timelock is not post-quantum; long-lived ciphertexts are exposed to harvest-now, decrypt-later (spec §7.7, §53). - Time confidentiality depends on drand's threshold assumption (spec §7.6). - `time_only` and `time_and_key` do not authenticate the creator (spec §36.1). In format 3 the declared author, the comment, the public note and the modification times are text of the creator that proves nothing (spec §24.1, §29.7, §55.1). - An author signature of `alg` 1 proves that someone with the secret key signed, not who holds it (spec §29.9, §29.12). For a signature with certificates (`alg` 2) and for a seal, the module checks the cryptography and the dates, never who issued a certificate or a seal, or whether it was revoked: an official validator does (spec §29.10, §29.11). Whoever can open a capsule can remake its security area, so only a valid seal says that it was signed before the date (spec §7.9). The verdicts never decide the opening (spec §29.3). - A key of words is as strong as its words: after the date, whoever holds the `.dkc` can try words offline (spec §38.1). - Opening a mature capsule years later needs the historical release (spec §50). - A compromised device can copy plaintext or secrets (spec §7.8). - Go cannot guarantee that secrets are erased from memory. The module wipes its own buffers (`I_PAYLOAD`, `CONTROL_CBOR`, `.dkk` material) on a best effort basis and promises no more. ## Cryptographic dependencies No cryptography is implemented in this module. It depends on: | Dependency | Role | |---|---| | `filippo.io/age` v1.3.2 | age files, X25519, STREAM, header MAC; scrypt for the files of author keys | | `github.com/drand/tlock` v1.2.0 | `TimeLock`, `TimeUnlock`, ciphertext encoding | | `github.com/drand/drand/v2` v2.1.7 | BLS verification (`crypto.Scheme`), chain-info hash | | `github.com/drand/kyber`, `github.com/drand/kyber-bls12381` | BLS12-381 pairing | | The Go standard library | `crypto/ed25519` (with the strict checks of `internal/ed25519strict`), `crypto/rsa`, `crypto/ecdsa` and SHA-2: author signatures and seals; `crypto/pbkdf2`: the key of words | Deterministic CBOR (spec §58) is implemented by the module itself, in package `codec`, without dependencies. So are DER and the reading of CMS signatures, X.509 certificates and RFC 3161 tokens (spec §29.10, §29.11), in `internal/der` and `internal/cms`: they read the structures with the profile of the specification, and the standard library verifies the signatures. All versions are pinned in `go.mod` and verified through `go.sum`. Changes to `age`, `tlock`, `drand` or `kyber` are reviewed manually. ### Known risks under watch - **`github.com/kilic/bls12-381` is archived.** `kyber-bls12381` builds on it, and both `drand` and `tlock` depend on that stack. Mitigation: pinned versions, `govulncheck` on every change and nightly, and this plan if a vulnerability appears or the dependency becomes untenable: (1) move to a maintained fork adopted by drand, or (2) extract BLS verification onto a maintained BLS12-381 implementation, keeping the golden vectors and fixtures as the acceptance test. - **`tlock` has had no tagged release since August 2024.** Only its exported core (`TimeLock`, `TimeUnlock`, `CiphertextToBytes`, `BytesToCiphertext`) is used, pinned by version. - **`drand/v2` brings gRPC and protobuf into the binary** through `common/chain`, used for the chain-hash self-check of profiles. With the `google.golang.org/grpc` v1.81.1 that `drand/v2` v2.1.7 selects, `govulncheck` reported GO-2026-6348 and GO-2026-6061 as reachable, so `go.mod` requires grpc v1.84.0, and `golang.org/x/crypto` v0.57.0 for GO-2026-6354 and GO-2026-6355. With those, `govulncheck` v1.8.0 on Go 1.26.8 finds no reachable vulnerability (25 September 2026); two unreachable advisories without a released fix remain, GO-2026-6443 (grpc) and GO-2026-5932 (x/crypto). Build with a patched Go toolchain: Go 1.26.0 itself has reachable standard-library advisories fixed in 1.26.1 and later. Plan §11 item 5 (extracting BLS verification onto `kyber-bls12381` alone) would remove gRPC from the graph entirely. - **Fixtures over past rounds** rely on the embedded signatures being genuine; every test run verifies them against the pinned public key. ## Supply chain - Reproducible builds: `-trimpath`, `CGO_ENABLED=0`, pinned toolchain in CI. - Releases publish SHA-256 checksums and a CycloneDX SBOM, and are signed with cosign using the project's signing key. - The Quicknet root of trust is compiled into the binary and checked against its pinned `profile_hash` (`4147645109798ecbc9f630c2f709835bb5846fe7911a6bd5c5755e25ade2ada4`).