Security of authentication material is the highest-priority invariant of this repository.
This repository is public. Any value committed, pasted into an Issue/PR, uploaded as an attachment, emitted to a public log, or included in an artifact must be assumed publicly disclosed.
The following MUST NOT appear in repository content, Git history, Issues, Pull Requests, review comments, Actions logs, artifacts, screenshots, test fixtures, examples, documentation, release files, or telemetry:
- real TOTP secrets
- real
otpauth://URIs - real
otpauth-migration://payloads - Google Authenticator migration QR codes or screenshots
- passwords, Wi-Fi SSID/password pairs, recovery codes
- PATs, OAuth tokens, API keys, access/refresh tokens, session credentials
- SSH/TLS/signing/private keys or seed material
- Vault Master Key (VMK)
- Passphrase-derived KEK
- Browser Unlock Key (BUK)
- Browser Registration Key (BRK) private key
- unlock/session key material
- user-generated encrypted Recovery Packages or other credential-bearing backups, even when ciphertext-only
- decrypted user Vault/account stores
- NVS, Flash, RAM, crash/core, serial, packet, or filesystem dumps that may contain credentials/keys
- any value that enables authentication, secret recovery, impersonation, or decryption of user secrets
If unsure whether a value is sensitive, treat it as sensitive and do not publish it.
docs/SECRET_VAULT.md is the canonical V1 Vault/key/unlock/recovery architecture.
- M5Authenticator V1 does not burn project-specific eFuse security material.
- Device Flash must not persist VMK, Passphrase, KEK, BUK, BRK private key, unlock/session keys, plaintext TOTP/Wi-Fi credentials, plaintext account identity metadata, or decrypted Vault snapshots.
- Device credential persistence is one authenticated Encrypted Vault ciphertext per generation plus bounded non-secret framing/registration metadata.
- issuer, account label, display name, TOTP profile/order, Wi-Fi SSID/password, and credential-id mapping belong inside the encrypted Vault.
- VMK exists on Device only in RAM while
UNLOCKED. - reboot/power loss, explicit Lock, fatal security error, Factory Reset, recovery provisioning, Trusted Browser replacement, and VMK re-key must wipe VMK and transient secret material.
- USB power/enumeration and ordinary Web Serial connection do not themselves Lock an unlocked Device.
- decrypted Vault plaintext must be bounded/transient for credential operations and must not remain resident for the full unlocked session.
- release firmware must never fall back to a public/synthetic development storage key.
- V1 Vault encryption uses AES-256-GCM with random 256-bit VMK, fresh random 96-bit nonce per encryption, and 128-bit tag.
- nonce must not be derived solely from generation.
- Vault AAD binds version/domain, logical
vault_id, storage schema, and generation. - Passphrase protection uses Argon2id v19 with the parameters defined in
docs/SECRET_VAULT.md, deriving a KEK used to AES-256-GCM-wrap the VMK. - newly created Recovery Passphrase wraps apply the bundled deterministic
weak-passphrase-policy-v1before Argon2id; it blocks only the specified obvious weak/repetitive/sequential/common classes and must not be described as entropy estimation or a strength guarantee. - existing Recovery Packages remain unwrap-compatible under the original NFC/framing/KDF contract even when their historical Passphrase would now be rejected for a newly created wrap; the weak-policy change must not alter Argon2id/AES-GCM/package format or VMK semantics.
- unsupported format/KDF parameters fail closed; do not silently reinterpret them.
- V1 permits exactly one active Trusted Browser registration per logical Vault/Device.
- BUK is browser-local/non-extractable and used only for the browser-local quick-unlock VMK wrapping path.
- BRK is a browser-local/non-extractable ECDSA P-256 private key used to authenticate fresh Trusted Browser unlock/registration transcripts.
- Device may persist only the BRK public key plus non-secret registration id/epoch.
- BUK and BRK private key are never exported in a Recovery Package.
- Browser replacement requires fresh Device user presence and invalidates the old BRK for future quick unlock.
- importing a Recovery Package alone must not create a second active canonical writer.
- VMK delivery uses fresh ephemeral P-256 ECDH, HKDF-SHA-256, and AES-256-GCM as defined by Decision #48 /
docs/SECRET_VAULT.md. - normal Trusted Browser quick unlock additionally requires a valid BRK signature over the current transcript.
- pending attempts are bounded and expire after 30 seconds.
- stale/replayed attempts, invalid signature/key/material, authentication failure, user rejection, timeout, cancel, superseding attempt, and disconnect fail closed and wipe pending session state.
- fresh Device physical confirmation is mandatory for initial registration, LOCKED quick unlock, new-Browser recovery, Trusted Browser replacement, and VMK re-key.
- a physical action from before the current request cannot authorize it.
- ordinary same-VMK canonical Vault generation updates while already
UNLOCKEDdo not require repeated physical confirmation merely because ciphertext changes.
- TOTP reveal requires both Device
UNLOCKEDand time-readinessREADY. READYis an operational readiness state and does not claim cryptographic source authenticity.- ordinary SNTP is retained as an explicitly unauthenticated network time source; DNS/gateway/Wi-Fi/UDP/NTP manipulation remains an integrity/availability risk.
- credential-backed NTP runs only while unlocked.
- after a current-boot anchor exists, NTP samples more than 300 seconds from monotonic-projected time are rejected without refreshing the anchor or 24-hour freshness lifetime; exactly 300 seconds remains acceptable.
- non-secret
time.statusmay be read while locked and reports source authenticity explicitly: NTP isunauthenticated_network, while USB islocal_host_asserted. local_host_assertedis not a cryptographic-authentication claim.time.syncmay mutate the time anchor only while unlocked; a locked USB host cannot pre-seed time, and the NTP jump rule does not apply to explicit USB correction.- a current-boot accepted anchor may survive explicit Lock but is cleared by reboot/power loss.
- rejected/failed resync does not extend freshness; more than 24 hours without an accepted sync remains fail-closed for OTP reveal.
V1 may export/import the Web canonical encrypted state as a Recovery Package. It must not contain plaintext credentials/VMK, Passphrase/KEK, BUK, BRK private key, or browser-specific material that bypasses Passphrase recovery.
A Recovery Package remains security-sensitive because theft permits offline Passphrase guessing. Passphrase change or VMK rotation cannot remotely erase/revoke a previously exported package. If leaked historical credentials must be invalidated, rotate/re-enroll them at the authoritative service/source and change affected Wi-Fi credentials.
- Public firmware images must not contain user secrets, shared production credentials, universal Vault keys, reusable release decryption keys, or browser private keys.
- Secrets are provisioned after flashing.
- TOTP/Wi-Fi plaintext and decrypted Vault data are opened only for the minimum practical lifetime and explicitly wiped afterward.
- Secret-bearing buffers must not be printed or included in assertions/errors.
- Debug builds do not get an exception to redaction rules.
- Production crash/core-dump behavior must not persist credential-bearing RAM in a way that defeats the RAM-only-key boundary.
- QR decoding and migration parsing happen locally.
- TOTP/migration/Wi-Fi plaintext, VMK, KEK, BUK, BRK private key, decrypted Vault data, and Passphrase material must never be sent to GitHub Pages or another server.
- Do not place sensitive values in URLs, query strings, fragments, analytics events, error reporting, or console logs.
- Plaintext credential/account records must not be persisted in browser storage.
- Browser persistence may contain Encrypted Vault, wrapped VMK values, version metadata, non-secret registration metadata, and non-extractable BUK/BRK keys as defined by
docs/SECRET_VAULT.md. - Recovery Package export/import is user-initiated and local-only; it must never be automatically uploaded.
- Imported QR images are ephemeral input.
- Network dependencies added to provisioning/security-sensitive paths require explicit security review.
- Release protocol must not provide stored TOTP/Wi-Fi/VMK/BUK/BRK-private export/read operations.
- Commands/responses avoid echoing secret values.
- Errors identify failure class/field without reproducing credential-bearing payload.
- VMK delivery is bound to a fresh session and never becomes a reusable plaintext operation.
- Trusted Browser quick unlock requires active BRK authentication and current Device user presence.
- Factory Reset is explicit/destructive and available only through the Provisioner in V1.
- Production USB Serial/JTAG is owned by the Protocol-v2 driver path rather than by ESP-IDF console/VFS stdio. Application logging, bootloader logging, stdout/stderr console output, and alternate production UART console routing must not share that transport.
- Before ownership is established,
PRE_HANDSHAKEaccepts only bounded synchronization for a strict-valid, current-version, read-onlyhello. Other production Protocol frames must not reach state-changing handlers before that handshake succeeds. - After a successful
hello, the link isSTRICT_POST_HANDSHAKE: framing is not salvaged around unexpected bytes, request id/version checks are not relaxed, and contaminated/malformed traffic fails the transport closed. - A faulted post-handshake transport cannot be recovered by another
helloon the same physical USB connection. The host must disconnect, reconnect, and perform a fresh handshake. - Production firmware does not reserve G43/G44 as an alternate console. Explicit diagnostics belong only to clearly non-production test/development profiles and must not masquerade as release configuration.
- ROM/pre-application residue is treated only as bounded pre-handshake synchronization input; M5Authenticator does not burn project-specific eFuse merely to suppress it.
Allowed:
- official/published public RFC/cryptographic test vectors
- clearly synthetic credentials generated only for tests
- synthetic QR payloads that cannot authenticate a real account
- synthetic VMK/KEK/BUK/BRK/session material generated only for tests
- synthetic Recovery Packages generated entirely from synthetic test credentials
Forbidden:
- personal authenticator exports
- real QR screenshots, even visually blurred
- user Recovery Packages, even encrypted
- production/user dumps
- credentials copied from local configuration
A fixture must remain safe if somebody decodes or prints it in full.
Never log:
- secret or encoded forms of secret
- complete credential-bearing
otpauth/migration payloads - Wi-Fi password
- VMK / KEK / BUK / BRK private key / session keys
- decrypted Vault/account records
- user Recovery Package contents
Issuer/account/display names and SSIDs may be personal data and are encrypted-at-rest V1 metadata. Prefer synthetic identifiers in tests/bug reports.
- Keep local secrets, Recovery Packages, backups, captures, and dumps in ignored local-only paths.
- Review staged changes before every commit;
.gitignoreand scanner checks are defense in depth, not authorization to store secrets locally in the repository tree. - Do not use actual credentials to reproduce a bug in public Issue/PR.
- Examples use unmistakably synthetic values.
- Generated build output/dumps/captures/local provisioning data must not be committed unless proven secret-free and intentionally versioned.
Any change affecting the following is security-sensitive and requires explicit review before merge:
- Vault format/storage/encryption/key wrapping/KDF/nonce/AAD/versioning
- VMK/KEK/BUK/BRK/session lifetime or zeroization
- Recovery Package format/import/export/Passphrase change semantics
- eFuse usage or any irreversible hardware security proposal
- lock/unlock/user-presence state machine
- Trusted Browser registration/replacement
- provisioning/import and Web Serial protocol
- browser persistence
- QR/migration parsing
- logging/diagnostics/crash dumps
- firmware update or Factory Reset
- Wi-Fi credential handling / trusted-time mutation
- BLE authentication/presence
- release/build/signing pipeline
- third-party/network dependencies in Provisioner
Security regressions are blocking defects even when functional verification passes.
If a real secret is exposed publicly:
- Assume it is compromised immediately.
- Revoke, rotate, replace, or re-enroll it at the authoritative source service.
- Remove exposed material from current repository/UI surfaces where practical.
- Review Git history, Actions logs, artifacts, Issues/PRs, caches, mirrors, and attachments for additional exposure.
- Determine how it crossed the trust boundary and add a preventive control/test.
Deleting/rewriting a Git commit or comment is not sufficient remediation because copies may already exist.
For a leaked TOTP secret, replace/re-enroll the affected 2FA credential at the service.
For an exposed encrypted Recovery Package, exposure does not prove plaintext compromise but creates an offline Passphrase-guessing target. If the package or its Passphrase protection is considered compromised, re-enroll affected source credentials; changing only the current M5Authenticator Passphrase cannot revoke the historical package.
For an exposed BUK/BRK/browser profile, replace the active Trusted Browser registration and assess the endpoint as compromised. Because endpoint compromise is outside the strong V1 guarantee, rotate/re-enroll underlying credentials when risk tolerance requires it.
This project aims to prevent accidental disclosure, common powered-off/rebooted-device loss/theft scenarios, Flash copying/dumping from directly revealing credentials, release-interface secret export, plaintext browser persistence, and passive/replayed unlock-material reuse.
It does not claim resistance to sophisticated physical extraction, RAM probing while unlocked, compromised endpoint OS/browser code, malicious extensions/XSS, active fake-device/Evil-Maid firmware replacement, hardware-backed rollback attacks, BLE relay, simultaneous source/device compromise, or realtime TOTP phishing. See PROJECT.md and docs/SECRET_VAULT.md.