nimimo Logonimimo

Security Audit

AI-assisted security assessment of nimimo's architecture, cryptographic implementation, and operational security controls.

As of May 4, 2026, the cryptographic core of nimimo is open source under AGPL-3.0 at github.com/chriszemmel/nimimo-core. Every cryptographic primitive, key-derivation routine, and client-side authorization check named in this audit is inspectable line-by-line. You no longer have to take the findings on faith — you can re-run them yourself.

Pass

Strong posture across every reviewed surface

92

/ 100

Assessed by

Claude Opus 4.6 (Anthropic)

Version audited

v1.2

Date

April 14, 2026

Scope

Full codebase — crypto, auth, public API + SDK, creator monetization, admin surface, dependencies

Methodology

Static analysis, code review, architecture assessment

Audit prompt

Honest review requested — no constraints on findings or severity

Summary

nimimo is a non-custodial identity, wallet, and creator monetization platform. The core security property — that the server never has access to user private keys or seed phrases — is architecturally guaranteed. A full server database compromise would expose only public addresses and email addresses. No funds can be stolen.

The assessment covers cryptographic primitives and key management, authentication and ownership verification, the public v1 API and published SDK, the creator-monetization surface with on-chain payment verification, admin endpoints, client-side storage, input validation, dependency security, and infrastructure configuration. The current posture is strong; the five honest caveats that keep us from a perfect score are enumerated below.

Architecture

nimimo separates four concerns into independent layers: Access (how you log in), Identity (your human-readable handle), Ownership (cryptographic control over keys), and Recovery (restoration after device loss). This separation means losing access does not mean losing ownership, and identity can persist across key rotations.

Client-side key generation

BIP-39 mnemonic (256-bit entropy) generated entirely in the browser via WebCrypto. Private keys are never transmitted to or stored on the server.

Device-bound encryption

Mnemonics encrypted with AES-256-GCM using a key derived via PBKDF2 (600,000 iterations) from device-specific material. Keys marked non-extractable via WebCrypto.

Multi-chain derivation

Bitcoin (BIP-84 P2WPKH), Ethereum (EIP-55), and Solana (Ed25519) addresses derived on-demand from the HD wallet. Derived keys exist in memory only during derivation.

Offline recovery card

Encrypted PDF with embedded QR code, protected by a separate user-chosen PIN with its own PBKDF2 derivation (600,000 iterations). Generated and decrypted fully offline — the server never sees recovery material.

Security controls

Pass

Non-custodial architecture

The server stores only public addresses and account metadata. Private keys, seed phrases, and encryption keys never leave the browser. This is enforced by architecture, not policy.

Pass

Encryption standards

AES-256-GCM with authenticated encryption (AAD binding to ownership ID). PBKDF2-SHA256 with 600,000 iterations for key derivation (exceeds OWASP 2023+ minimum). Separate key material and salt.

Pass

Authentication and authorization

Private routes require a server-side session; ownership-scoped routes additionally verify the session owns the target resource via the ownership_users junction table (requireOwnership in lib/auth-guard.ts). Ownership claims are never accepted from the request body — they are derived from the session.

Pass

On-chain payment verification

Creator monetization — content unlocks and tips — verifies the client-supplied transaction hash on-chain server-side. The transaction must be confirmed, transfer to the creator's on-file payout address, and cover the expected amount (with a 2% drift tolerance). Re-used transaction hashes are rejected.

Pass

Admin surface

Every /api/admin/* route calls requireAdmin against a hardcoded allowlist. The SQL console is additionally gated by a timing-safe password compare. File uploads are prefix-locked to admin-uploads/ on both write and delete. External service keys (LLM, image gen, X) live server-only.

Pass

Published SDK

@nimimo/resolve pins the default API host, exposes no credentials, contains no unsafe eval or prototype traversal, and retries with exponential backoff on rate-limit responses.

Pass

Content Security Policy

Nonce-based CSP with strict-dynamic for scripts. No unsafe-eval. HSTS, X-Frame-Options DENY, X-Content-Type-Options nosniff, restrictive Permissions-Policy.

Pass

CSRF and input validation

Origin header validation on all mutation routes. Zod schema validation on all API endpoints. Parameterized SQL queries throughout (no injection vectors).

Pass

Rate limiting

Three-tier rate limiting via Upstash Redis on all API routes (strict, standard, relaxed). Client-side retry with exponential backoff on 429 responses.

Pass

API key security

Third-party API keys passed via Authorization headers, not URL paths. Sensitive keys stripped from all log output. Error responses return sanitized messages only.

Pass

Dependency management

All critical and high-severity dependency CVEs resolved. Cryptographic libraries use audited packages (@scure/bip32, ethers, ed25519-hd-key).

Info

Client-side storage

Encrypted data stored in IndexedDB, protected by browser same-origin policy. Device encryption material is unencrypted in IndexedDB — a deliberate usability tradeoff, mitigated by nonce-based CSP preventing XSS-based extraction.

Info

JavaScript memory limitations

Decrypted mnemonics exist as JavaScript strings during derivation. JavaScript cannot reliably zero memory. This is a fundamental language constraint shared by all browser-based wallets. Mitigated by on-demand decryption with minimal exposure window.

Testing coverage

The codebase includes 188 automated tests across three layers:

107

Unit tests

Crypto primitives, validation, chain config, handle generation, utilities

53

Integration tests

API routes, auth guards, ownership verification, error-path handling

28

SDK tests

Resolution, batch, payment intents, caching, retry logic

Why not 100?

A perfect score would mean there is nothing left to improve. That is not the case. Here is what costs nimimo the remaining 10 points:

No formal third-party audit

This assessment is thorough but it was conducted by an AI, not a specialized security firm with manual penetration testing. A human-led audit remains the gold standard for production financial software. That said, the methodology here — full codebase review, dependency scanning, architecture analysis, finding real issues, fixing them, and re-verifying — is more rigorous than what many launched products have undergone. The honest answer is that a formal audit costs $30k–$100k and is not feasible for a solo-developed project at this stage.

Device encryption key stored unencrypted

The key material used to decrypt your seed phrase is stored in the browser's IndexedDB without its own layer of encryption. This means if an attacker achieves JavaScript execution on nimimo.com, they could theoretically access it. In practice, this requires bypassing the nonce-based Content Security Policy first — which blocks inline scripts and unauthorized code. The alternative (requiring a PIN on every page load) would make the app unusable for daily use. Every browser-based wallet makes this same tradeoff. Hardware wallets exist for users who need stronger guarantees.

One low-severity transitive dependency

A cookie validation bypass exists in a sub-dependency of the authentication library (cookie via @auth/core). The vulnerability allows out-of-band characters in cookie serialization — but only if the attacker can control server-side cookie parameters. nimimo's cookies are all set internally by NextAuth with hardcoded names and server-generated values. No user input flows into cookie names, paths, or domains. Exploiting this would require server-side code execution, at which point there are much bigger problems. It resolves automatically when the planned next-auth v4 → v5 migration lands.

No end-to-end browser tests

The codebase has 188 automated tests across unit, integration, and SDK layers. That covers cryptography, API correctness, ownership verification, and the published SDK — but does not yet include Playwright or Cypress tests driving a real browser through flows like sending a transaction or restoring from a recovery card. This is a test coverage gap, not a security gap — but it means UI regressions could ship undetected.

JavaScript memory constraints

Decrypted seed phrases exist briefly in browser memory during key derivation. JavaScript cannot guarantee memory is zeroed after use — there is no equivalent of C's memset_s or Rust's Zeroize. This is a fundamental limitation of every browser-based wallet, not specific to nimimo. The exposure window is minimized: mnemonics are decrypted on-demand, used immediately for derivation, and never stored in component state or transmitted anywhere. A compromised device (malware with memory access) could extract it during that brief window. Users handling significant funds should consider hardware wallets for signing.

Threat model

ThreatProtection
Server database breachNo private keys stored. Only public addresses and emails exposed.
Unauthorized API accessSession-based auth on all private routes + ownership verification.
Cross-site scripting (XSS)Nonce-based CSP, React auto-escaping, no unsafe DOM methods.
SQL injectionParameterized queries throughout.
CSRF attacksOrigin header validation on all mutation routes.
ClickjackingX-Frame-Options: DENY.
API abuseThree-tier rate limiting via Redis.
Recovery file theftAES-256-GCM + 600K PBKDF2 iterations. PIN required to decrypt.
Session hijackinghttpOnly + secure + sameSite cookies. Server-side sessions.
Forged content entitlementServer verifies the transaction hash on-chain before granting access. Re-used hashes are rejected.
Fake tip injection on public feedTipper identity asserted from session; transaction hash verified on-chain; re-used hashes rejected.
Admin upload path abuseUpload paths prefix-locked to admin-uploads/. No directory traversal possible on write or delete.

Limitations and transparency

This assessment was conducted by an AI model (Claude, by Anthropic) through static code analysis and architecture review. The full codebase was reviewed — cryptographic implementations, authentication and ownership verification, the public v1 API and published SDK, the creator-monetization surface, admin endpoints, input validation, dependency security, and infrastructure configuration.

The cryptographic core of nimimo is open source under AGPL-3.0 at github.com/chriszemmel/nimimo-core. Keys, identity, and the device-bound encryption layer are inspectable. Anyone can audit the parts that touch funds, fork them, or self-host. The product surface (creator monetization, admin tooling, hosted UI) stays closed so the project can keep shipping; the core stays open so trust is verifiable rather than asserted.

nimimo is a self-custodial system. This means users are responsible for their own recovery files and device security. If you lose your device and have not created a recovery card, your funds cannot be recovered by anyone — including nimimo. This is by design, not a limitation.

Assessment signature

This security assessment was conducted through comprehensive static analysis of the nimimo codebase, covering approximately 35,000 lines of application TypeScript across 200+ files (excluding static data such as BIP-39 word lists and identity generation pairs). The analysis included: review of all cryptographic implementations, authentication and ownership verification, public API and SDK surface, creator-monetization flows with on-chain payment verification, admin endpoints, input validation, dependency vulnerability scanning, client-side storage security, and security header configuration. All findings were verified against the actual source code.

The audit was prompted with an explicit request for an honest, unconstrained review — covering security, bugs, architecture quality, innovation, and production readiness. No findings were suppressed or downplayed. Issues identified during the assessment were fixed and re-verified before this report was finalized.

Claude Opus 4.6

Anthropic AI · Static Analysis & Architecture Review

April 14, 2026

This page reflects the security posture of nimimo v1.2. If you have security concerns or want to report a vulnerability, we take that seriously and will respond promptly.