This document is print-optimized. Export opens your browser Save as PDF flow.
Technical architecture, trust boundaries, and control mapping for a server-side encrypted personal finance platform.
Public technical brief
Version
2026.03
Updated
March 7, 2026
Scope statement
This document describes the security controls visible in the current product implementation and clarifies both the protections and the explicit trust assumptions of the platform.
Actions
Format: browser-generated PDF export
Selected language: English
Recommended use: technical due diligence, risk review, and architecture validation.
Summary
Key findings
Abbreviations
AES-GCM
Authenticated symmetric encryption mode used for protected user fields.
API
Application Programming Interface.
CSP
Content Security Policy.
HSTS
HTTP Strict Transport Security.
MFA
Multi-Factor Authentication.
RLS
Row-Level Security.
TLS
Transport Layer Security.
UUID
Universally Unique Identifier.
List of tables
Table 1. Application-layer encrypted domains
Table 1 included in the main body of the document.
Table 2. Request and platform controls
Table 2 included in the main body of the document.
Table 3. Threat model boundary summary
Table 3 included in the main body of the document.
Table 4. Public control comparison with selected fintech platforms
Table 4 included in the main body of the document.
Mova is implemented as a Next.js application where privileged data access is concentrated in server-side API routes. The browser can authenticate with a user session, but it is not intended to receive service-role database credentials or execute privileged Supabase operations directly.
The security model combines multiple layers: bearer-token validation, same-origin protections for mutating requests, request throttling, strict response cache behavior, database row-level security, and application-layer encryption for user-owned financial fields.
A typical protected request flows through the browser, into the application API, through request safety checks, then into server-side Supabase access. The trust boundary is therefore the server runtime, not the client bundle. Public routes are deliberately limited to a small set of read-only market or health endpoints.
Because the service role key is server-only, a copied frontend bundle or database URL does not provide the material required to perform privileged reads. This materially narrows the blast radius of common client-side leaks.
For protected financial tables, secure fields are serialized into encrypted_data before persistence. The runtime derives a per-user AES-GCM key from the service secret, the user identifier, and a unique profile salt. Decryption happens only inside authorized server requests.
This design means a direct table dump still exposes structural metadata such as row identifiers and timestamps, but protected business fields remain opaque without the server-side secret and key-derivation path.
The internal API dispatcher rejects invalid path segments, blocks reserved prefixes, enforces same-origin checks on mutating methods, applies a one-megabyte body limit for the generic API surface, and responds with no-store cache headers for API traffic.
Rate limiting is currently implemented in-process with a 60-second window and route-scoped keys derived from client IP, authentication state, and route prefix. This is effective for a single runtime instance and should be understood as a practical application control rather than a distributed edge control.
Invoice uploads are handled through dedicated server routes instead of client-side direct bucket writes. The route validates same-origin mutations, requires an authenticated user, restricts MIME types to a short allowlist, and limits upload size to ten megabytes.
Files are stored under user-scoped paths and later exposed with signed URLs. This reduces open bucket enumeration risk and avoids exposing raw object paths as publicly retrievable resources.
Administrative routes are protected by both authentication and an admin-role check. User access changes, feedback actions, and other privileged events are inserted into admin_audit_logs só that privileged operations have a reviewable trace.
The platform also includes re-encryption flows for user data. This is operationally valuable for migration, data repair, or cryptographic maintenance because it gives the operator a defined procedure instead of requiring one-off direct database manipulation.
A browser-only attacker, a leaked client bundle, or a database operator with row access but without server secrets should not be able to read protected financial fields in plaintext. That is the practical security value of the combined server-only secret and per-user encrypted blob design.
A fully privileged production operator with runtime secret access remains inside the trust boundary and can execute authorized decryption logic. The design therefore does not claim zero-knowledge privacy. A security review should treat this as a hardened confidential-server model, not as client-held end-to-end cryptography.
The comparison tables in this brief do not claim parity of scope with regulated banking platforms. They are intended to show that Mova follows a recognizable set of control families publicly described by established fintech products: encrypted transport, protected sessions, restricted staff access, and explicit fraud or monitoring practices.
The public-vendor columns below are based on official vendor security or privacy documentation available on March 7, 2026. They are illustrative and should not be interpreted as a substitute for an independent vendor audit.
If the product requires a stronger privacy posture against privileged server operators, the next architectural step would be client-held encryption keys or a zero-knowledge design. That would significantly change search, recovery, and administrative workflows and should be treated as a product-level tradeoff, not a small patch.
If the product requires stronger abuse resistance at scale, distributed rate limiting, WAF-backed anomaly controls, dedicated secret rotation workflows, and formal external penetration testing should be added to the current foundation.
| Domain | Protected field families | Reason for protection |
|---|---|---|
| Cards | Name, type, bank, last four, balances, maintenance fee, maintenance cadence, color, currency | Prevents plaintext exposure of payment instrument metadata and stored balances. |
| Transactions | Type, amount, description, date, currency, allocations, recurring flags, invoice metadata | Protects ledger details, categorizations, and uploaded invoice references. |
| Income and expenses | Names, types, amounts, frequency, category, alert fields, currency | Protects recurring cashflow sources and operational reminders. |
| Assets and investments | Names, types, values, purchase dates, institution data, notes, return metrics, currency | Protects portfolio composition and valuation history. |
| Liabilities and goals | Names, remaining balances, payment fields, notes, target amounts, dates, priorities, currency | Protects debt structure and financial planning targets. |
| Tax records | Year, gross income, deductions, tax paid, tax rate, notes | Protects sensitive compliance and reporting inputs. |
The database still stores row identifiers and some operational metadata in plaintext; the sensitive business fields above are persisted inside encrypted_data.
| Control | Current implementation | Security objective |
|---|---|---|
| Bearer-token validation | Protected routes require a valid Supabase bearer token before dispatch. | Reject anonymous access to user or admin resources. |
| Same-origin mutation gate | POST, PATCH, PUT, and DELETE requests are checked against the request host origin. | Reduce cross-site request abuse for authenticated browser sessions. |
| Path safety enforcement | Unsafe segments and reserved prefixes are rejected before internal routing. | Reduce path traversal and accidental route exposure. |
| Body-size limits | Generic API bodies are capped at 1 MB; invoice uploads are capped at 10 MB. | Bound memory pressure and oversized-request abuse. |
| Rate limiting | 180 requests per 60 seconds per route key, keyed by IP plus auth state. | Throttle abuse and reduce trivial flooding. |
| Security headers | CSP, HSTS in production, frame denial, nosniff, strict referrer policy, and limited permissions policy. | Harden browser execution and transport policy. |
| Response caching | API responses are served with no-store semantics. | Reduce sensitive response persistence in shared or stale caches. |
| Scenario | Expected access to plaintext | Expected resistance |
|---|---|---|
| Leaked browser bundle or frontend source | No service-role secret; no direct privileged reads. | Strong resistance, assuming server secrets remain protected. |
| Raw database dump without server secret | Encrypted blobs remain unreadable for protected financial fields. | Strong resistance for covered fields, with structural metadata still visible. |
| Compromised authenticated end-user browser session | User can access only their own decrypted records through the application. | Contained by bearer auth and database/user scoping, but user-session abuse remains possible. |
| Routine support or dashboard access without server runtime privileges | No direct plaintext from encrypted financial blobs. | Meaningfully reduced exposure versus plaintext-at-rest systems. |
| Privileged production operator with runtime secret access | Can derive per-user keys and execute server-side decryption flows. | Inside trust boundary; this is a residual risk and not claimed to be impossible. |
| Control family | Mova | Wise | Revolut | Monzo |
|---|---|---|---|---|
| Server-only privileged secrets | Yes. Service-role key is server-only by design. | Public docs describe restricted internal access and encrypted storage, but server-secret model is not described in product terms. | Public docs describe secure server-side handling and restricted access. | Public docs describe app/device protections; server-secret model is not described in product terms. |
| Encrypted transport and protected storage | Yes. TLS-backed transport plus application-layer encrypted financial fields and database RLS. | Publicly states personal data is encrypted in transit and at rest. | Publicly states information is encrypted and stored on secure servers. | Publicly states security controls around app access; public storage-encryption wording is less detailed. |
| Session hardening and user auth controls | Bearer-token validation on protected routes; admin checks on privileged routes. | Publicly documents 2-step login and verification controls. | Publicly documents app passcodes, biometrics, and security verification. | Publicly documents fingerprint or Face ID app locks and instant card freeze. |
| Monitoring, fraud, or abuse operations | Route throttling, audit logs, and explicit re-encryption/ops pathways. | Publicly documents security monitoring, incident handling, and bug bounty reporting. | Publicly documents anti-fraud monitoring and 24/7 security response features. | Publicly documents card freeze and real-time app controls; public threat-monitoring detail is narrower. |
| Zero-knowledge claim | No. Not claimed. | No public zero-knowledge claim. | No public zero-knowledge claim. | No public zero-knowledge claim. |
Vendor columns are based on public security or privacy documentation, not on private architecture reviews. The comparison is illustrative rather than exhaustive.
Wise Privacy and Security
Public statements about encryption in transit and at rest, SOC 2 Type 2, PCI DSS, restricted employee access, and security monitoring.
https://wise.com/gb/privacy-policyWise Bug Bounty Program
Public disclosure of coordinated vulnerability reporting and bounty incentives.
https://wise.com/gb/blog/introducing-our-bug-bounty-programmeRevolut Safety and Security
Public statements about encrypted information, secure servers, biometrics, anti-fraud controls, and security workflows.
https://www.revolut.com/en-US/how-we-keep-your-money-safe/Monzo Biometrics and App Lock
Public statements about device biometrics and app-lock behavior.
https://monzo.com/help/security/biometrics/Monzo Keeping Your Money Safe
Public statements about card freeze controls and protective account workflows.
https://monzo.com/help/us-account-and-profile/us-keeping-your-money-safe/Internal Mova implementation
Current application code paths and schema configuration: API gateway checks, application-layer encryption, admin audit logging, and storage access controls as of the update date above.
https://mova.ao/privacy-policyDisclaimer
This brief is technical but public. It describes implemented controls and trust assumptions. It is not a formal external certification, penetration-test report, or guarantee against every class of privileged compromise.