Spine ships cryptographic verification code that runs in browsers, on the command line, and inside production WAL-pipeline servers. We take security reports seriously and welcome scrutiny. Finding a real flaw here is high-value work, and a verifier that lies is worse than no verifier at all.
Email: security@eulbite.com
Please do not open a public GitHub issue for security reports. The standard channel is email; if you cannot use email, request a private discussion thread by opening a non-descriptive issue ("requesting private security disclosure channel") and we will respond there with a way to share details privately.
We aim to:
- Acknowledge the report within 3 business days.
- Assess severity and reproducibility within 10 business days.
- Patch within 90 days for confirmed high/critical findings, faster for active exploitation. We coordinate timing with the reporter; early publication is fine when the issue is mitigated or low risk.
If you do not hear back within the acknowledgement window, please follow up, as your report may have been caught by a spam filter.
The following components, when used as documented:
spine-core: the verification library.- Soundness of
verify_demo_wal(strict) andverify_wal_bytes(lenient): chain replay, signature verification, payload-hash recomputation, canonical-JSON serialisation. - Memory safety / panic paths reachable from public APIs. The
crate is
#![deny(clippy::unwrap_used)]by policy; any documented public input that produces a panic is in scope. - Test-vector conformance (
test-vectors/vectors.json): a case where the verifier does not reproduce a pinned canonical-JSON, entry-hash, or signature value. The vectors are the wire contract; a divergence is a correctness bug.
- Soundness of
spine-wasm: the WebAssembly façade.- The JS-callable surface (
verify_demo_wal_json,verify_wal_bytes_json) and its JSON envelope. - Bundle-integrity issues that survive the documented bootstrap (manifest-pinned hashes, Blob-URL dynamic import).
- The JS-callable surface (
spine-cli: the offline auditor binary.- Verification correctness; export integrity (the manifest that accompanies a JSONL export must commit to a digest of the full source WAL, distinct from the filtered subset).
playground-spec/: the integration contract.- Documented bootstrap order and integrity-check flow.
- The reference React component's integrity logic (manifest + SHA-256 + Blob-URL dynamic import). Cosmetic React issues are not security; bypasses of the integrity flow are.
demo-seeder: the offline seeding tool.- Key-handling hygiene (no key bytes on disk, zeroize-on-drop, interactive prompts before display).
- Self-verify guard: the binary refuses to write outputs that
fail
verify_demo_walagainst its own freshly-computed pubkey/root.
These are not security issues against this repository:
- Operational integrity of any specific Spine deployment.
Misconfiguration of a host site's CSP, SRI, cache, or asset
pipeline is the deploying site's responsibility. See
playground-spec/INTEGRATION.md§ 7 for the documented requirements. - Key-management, HSM integration, key rotation, or multi-signer flows. None of that lives here.
- Compliance certifications.
- Misuse of the lenient
verify_wal_bytesin a context that required pinning. The default lenient entry point is policy-free (an opt-intrusted_pubkeypin andexpected_rootanchor exist but are off by default); using the unpinned path where strict pinning is needed is a usage error, not a vulnerability. - DoS reports against the lenient CLI auditor on adversarial
inputs. The strict path has documented hard limits
(
MAX_RECORDS_DEMO,MAX_PAYLOAD_BYTES); the lenient path does not, by design, because it processes large production WALs. - Issues that require the attacker to already have the demo signing private key, or to control the deploy host's filesystem. Those threat models are documented as outside the verifier's scope.
After a reported issue is patched and the fix is published, we publish a brief advisory in the repository's GitHub Security Advisories. Reporters are credited by name (or pseudonym) with their consent; if you prefer to remain anonymous, say so in your report and we will respect that.
We do not currently run a paid bug bounty programme. We do acknowledge significant contributions in release notes and on the project's launch page.
The most consequential class of report against this codebase is a
verifier that returns valid:true on a WAL that should be
detected as tampered, or a verifier that fails to detect a
specific class of tampering. Examples that would qualify:
- A WAL whose canonical-JSON serialisation does not match the pinned test vectors, so a payload-hash check passes when it should fail (or fails when it should pass).
- A signature scheme mismatch where bytes signed by the strict contract verify under the lenient one (or vice versa). The two contracts are namespaced by domain separator precisely to make this impossible; a counterexample would be a serious finding.
- A chain-root computation that ignores ordering, allowing record re-arrangement to produce the same digest.
- A timing side channel in pubkey or chain-root comparison that leaks the pinned value.
If you find anything in the neighbourhood of those, please report even if you are not 100% sure. False positives cost us an hour; false negatives cost us the project.