mirror of
https://github.com/PR0M3TH3AN/bitlogin.git
synced 2026-10-30 18:11:21 +00:00
crypto/random.ts is the single chokepoint for every secret this codebase mints -- recovery entropy, everyday keys, vault roots, AEAD nonces, account ids, generated passphrases. It is correct today: it throws when no secure source exists rather than falling back, and rejection-samples to avoid modulo bias. Nothing in CI would have reported it if either stopped being true. That is the gap this closes. The existing suite is strong on known-answer vectors -- HKDF, ScalarExpand, Argon2id, BIP-39, Schnorr, GCM tamper detection, NIP-44 official vectors -- but every one of them is satisfied by a deterministic stream. Same input, same output. That is exactly how a predictable RNG survives a health check that only asks whether the output looks random. Adds two blocks, nine tests: - Fail-closed: no crypto object, crypto without getRandomValues, and getRandomValues present but not callable must each throw, and randomEntropy128 / generatePrivateKey / randomUniformInt must abort rather than substitute a value. Plus a check that normal operation resumes once a source is available again, so the guard cannot be satisfied by breaking everything permanently. - Uniformity: chi-square over 200k draws at modulus 94, full-range coverage at the EFF wordlist modulus of 7776, rejection of invalid bounds, and the degenerate modulus of 1. Both mutation-verified rather than assumed. Replacing the throw with a zero-filling stub turns five fail-closed tests red. Replacing rejection sampling with a bare `value % maxExclusive` gives chi-square 5614 against a threshold of 147 -- while leaving every other test in the suite green, which is the whole reason the distribution test has to exist. Tests only; no source or behaviour change. Suite 172 -> 181. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
84 lines
4.2 KiB
Markdown
84 lines
4.2 KiB
Markdown
# BitLogin — open items
|
|
|
|
Updated: 2026-07-31
|
|
|
|
## Entropy audit (2026-07-31)
|
|
|
|
[`entropy-audit-2026-07-31.md`](./entropy-audit-2026-07-31.md) — RNG and
|
|
randomness-integration audit. **No predictable-fallback defect:** `random.ts`
|
|
is the single chokepoint, throws rather than degrading, and rejection-samples to
|
|
avoid modulo bias. Three hardening items, in order:
|
|
|
|
- **M2 — done.** Nine tests in `packages/core/src/crypto/crypto.test.ts` pin
|
|
fail-closed behaviour and `randomUniformInt`'s uniformity. Mutation-verified:
|
|
a zero-filling stub in place of the throw turns five of them red, and
|
|
swapping rejection sampling for bare modulo gives chi-square 5614 against a
|
|
threshold of 147.
|
|
- **M1** — `nonceOverride` / `ivOverride` are reachable from the public
|
|
`@bitlogin/core/crypto` surface. Move behind a non-exported test module.
|
|
- **L1** — `Math.random` in the backup-quiz word picker (`element.ts:1471`).
|
|
Not a secret, but it forces a standing exception in any `Math.random` ban rule.
|
|
|
|
## Owner action items
|
|
|
|
1. **Close the Dependabot PR on
|
|
`dependabot/npm_and_yarn/npm-security-and-maintenance-83024bc549`.** It
|
|
bundles seven major bumps into one change (`@noble/hashes` 1.8→2.2,
|
|
`@noble/curves` 1.9→2.2, `@scure/base` 1.2→2.2, `@scure/bip39` 1.6→2.2,
|
|
TypeScript 5→7, Vite 6→8, Vitest 3→4) and fails the build: noble v2 dropped
|
|
the extensionless subpath exports this code imports. It should be closed,
|
|
not merged or fixed — `.github/dependabot.yml` now groups only minor/patch
|
|
and ignores majors of the derivation chain, so this PR will not recur.
|
|
|
|
The four `dependabot/github_actions/*` PRs are unaffected and fine to merge.
|
|
|
|
2. **Decide whether the manual-password removal is final.** User-chosen
|
|
passwords were removed entirely (not merely discouraged) in the 2026-07-31
|
|
hardening, and `packages/widget/src/securityPolicy.test.ts` pins that. The
|
|
security argument is sound — a user-chosen password against a downloadable
|
|
capsule is offline-guessable forever — but it is a product decision that
|
|
changes what users can do, and it is now enforced by a test rather than by
|
|
preference.
|
|
|
|
## Standing rule: the derivation chain is a compatibility contract
|
|
|
|
Account capsules live on public relays. The login name plus password derive the
|
|
locator, signing scalar and capsule key deterministically, so those outputs are
|
|
a contract with every account that already exists — change them and users are
|
|
locked out permanently, with no server-side record to migrate from.
|
|
|
|
`packages/core/src/crypto/knownAnswer.test.ts` pins HKDF-Extract, HKDF-Expand,
|
|
ScalarExpand (scalar, counter, and resulting public key), BIP-39 phrase and
|
|
seed, base64url framing, and JCS ordering.
|
|
|
|
**A failure there is never "update the expected value".** It means the change
|
|
being attempted is account-breaking and needs a migration plan or rejection.
|
|
The rest of the crypto suite only checks self-consistency — same input, same
|
|
output within one run — which stays green through exactly the kind of upgrade
|
|
that would lock everyone out.
|
|
|
|
## Deferred hardening
|
|
|
|
Carried from the 2026-07-30 audit; none are live defects.
|
|
|
|
- **Tier 2** — `packages/widget/src/element.ts` is ~1,600 lines with no direct
|
|
test coverage. `securityPolicy.test.ts` now asserts a few properties of its
|
|
source text, which is a start, not coverage.
|
|
- **Tier 3** — compare-and-swap on capsule writes (relays offer no atomic
|
|
primitive, so this needs a protocol-level answer), and an encrypted
|
|
high-water-mark store.
|
|
- **Tier 4** — moving high-value authorization into a cross-origin or extension
|
|
boundary. An embedded widget is same-origin with its host page, so a
|
|
compromised host can reach the worker directly. Documented honestly in
|
|
`llms.txt` and the README rather than papered over.
|
|
|
|
## Gates still in force
|
|
|
|
- **External security review before the vault holds anything beyond a
|
|
budget-capped NWC connection.** The S3 and password profiles stay designs
|
|
until then.
|
|
- Personal-tier UI was gated on the sudo key leaving the credential capsule.
|
|
That gate is now **met** — the sudo key lives only in the phrase-gated
|
|
recovery capsule — but the UI still needs a separately reviewed key
|
|
ceremony before it ships.
|