v4.0.0 — Security release
Security release fixing three critical, exploitable vulnerabilities in the GDAF Verifiable Credential path, removing a live private key, hardening crypto, and repairing the test runner. Full suite: 4172 passing, 0 failing.
🔴 Critical (GDAF credentials)
- Signatures now cover the whole credential body. Canonicalization used the
JSON.stringifyreplacer-array form, which dropped every nested object (credentialSubject→{}) from the signed hash — claims could be rewritten without invalidating the proof. Replaced with a recursive, depth-complete key sort. - The signature is now actually checked. Verification read the always-truthy
ECDSA#verify()instance instead of.verified, so every proof passed regardless of validity. - Signing key is bound to the issuer. Key was resolved from the attacker-controlled
proof.verificationMethodand never compared tocredential.issuer(issuer spoofing).trustedIssuersis now enforced.
🔑 Key removal
- Deleted
utilities/wallet.json(shipped a live mainnet WIF) and added a.gitignoreguard. Rotate that key — treat as compromised.
🟡 Hardening
- ECIES (electrum/BIE1): constant-time MAC comparison.
ECDSA#sigError: removed dead branch; rejects negativer/s(range[1, n-1]).- Dropped inaccurate
vulnerability-free/security-hardenednpm keywords.
🧪 Tests / tooling
- Added
.mocharc.json(recursive) + removed defuncttest/mocha.opts— mocha 8 ignoredmocha.opts, so ~40 test files never ran in CI. - Repaired
test/crypto/security.js(0/8 → 12 passing); addedtest/gdaf/canonicalize.js(8 tests); fixed the 18 pre-existing failures.
⚠️ Breaking
The signed bytes changed (nested claims now covered), so credentials/presentations signed by ≤ 3.4.5 will not verify under 4.0.0. Re-issue them.
Full changelog: see CHANGELOG.md.