Email security@forgesworn.dev (or open a private security advisory on GitHub). Please do not open public issues for vulnerabilities.
nsec-tree-py has not had an independent third-party security audit. It is conformance-tested against the protocol's frozen vectors and cross-verified byte-for-byte against the TypeScript reference implementation, but you should review it yourself before protecting high-value keys.
- Deterministic, cross-implementation derivation (Python↔TS interop test-proven); domain-separated HMAC with null-byte delimiters — unambiguous, no cross-purpose collision.
- Signing/derivation-key separation:
from_nsecHMACs the nsec into the root; the hierarchy re-runs the HMAC, so a leaked child key does not expose the parent signing key. - Only valid secp256k1 keys are produced (reject-and-retry, bounded; never invalid or hang).
- Unforgeable BIP-340 linkage proofs over a canonical, injection-resistant attestation; fail-closed verification.
- Hardened event/proof parsing: duplicate-tag rejection, strict integer indices, newline-rejecting hex validators, and p/d/pubkey cross-checks.
- No secret-dependent equality comparisons in the Python layer; no secret material echoed in exceptions or tracebacks.
- Secrets at rest / in memory — zeroisation is best-effort only. CPython cannot
scrub immutable
bytes/strobjects in place; mnemonic seeds and BIP-32 intermediates persist until garbage-collected and may be paged to disk. Prefer short-lived secrets. - Side channels / timing — pure-Python paths are not guaranteed constant-time. No
exploitable secret-dependent branch was identified during review, but no constant-time
guarantee exists. secp256k1 operations run in
libsecp256k1(C viacoincurve). - Entropy of the source secret — the library derives from whatever nsec or mnemonic it is given; it neither generates secrets nor assesses their entropy.
- Underlying primitives and supply chain —
coincurve/libsecp256k1,bech32,mnemonic, andbip32are trusted. A backdoored dependency could exfiltrate or weaken keys. Dependencies are floor-pinned (>=) with no upper bound; hash-pinning and supply-chain vigilance are the consumer's responsibility.
coincurve (→ libsecp256k1), bech32, and — for the optional mnemonic path —
mnemonic and bip32. Pin versions in production.