BETA Early Access — 25 individual + 5 IFA founding places (5 clients each). 6 individual & 4 IFA spots left! Claim Your Spot →

Security at Wealth365

Your financial data is sensitive. We take its protection seriously. The measures described on this page reflect the security controls built into our platform.

All systems operational

Data Encryption

Your information is protected at every layer

🔐

Field-Level Encryption

Sensitive personal and financial fields are encrypted at the individual field level using Fernet symmetric encryption (AES-128-CBC with HMAC-SHA256). This means even if someone gained access to our database, protected information would be unreadable ciphertext.

Implementation: Fernet via Python cryptography library. Each encrypted value carries its own authentication tag, preventing tampering.
🔑

Password Hashing

Your password is never stored — not even in encrypted form. Instead, we use bcrypt, a deliberately slow, adaptive hashing algorithm designed specifically for passwords. Even we cannot recover your password; we can only verify it.

Implementation: bcrypt via Flask-Bcrypt with automatic salting. The work factor increases computational cost to resist brute-force attacks.
🌐

Transport Encryption

All connections to Wealth365 are encrypted with TLS (HTTPS). Session cookies are flagged as Secure, meaning they are never transmitted over unencrypted connections.

Implementation: SESSION_COOKIE_SECURE = True. HTTPS enforced at infrastructure level.

Session & Access Controls

Strict controls to protect your account from unauthorised access

🍪

Secure Session Cookies

Sessions use HttpOnly cookies (inaccessible to JavaScript), SameSite=Lax (prevents cross-site request attacks), and are transmitted only over HTTPS.

Flags: Secure, HttpOnly, SameSite=Lax
⏱️

Session Timeouts

Sessions are configured with an 8-hour lifetime and a 30-minute idle timeout — if you step away from your computer, your session expires automatically. Concurrent session limits prevent unauthorised reuse of credentials.

Settings: Configured 8-hour session lifetime. 30-minute idle timeout. Concurrent session limits enforced per user.
🚦

Tiered Rate Limiting

Key endpoints are rate-limited to prevent brute-force attacks, credential stuffing, and abuse. Different tiers apply to different areas of the application, with dedicated throttling on login and registration.

Limits: Admin: 30 req/min | API: 60 req/min | Pages: 120 req/min
🔒

Account Lockout

After repeated failed login attempts, accounts are temporarily locked to prevent brute-force password guessing. Users are notified and can recover through the password reset flow.

Implementation: Failed login tracking with automatic lockout. Password history prevents reuse of the last 5 passwords.

Application Security

Defence in depth across the application layer

🛡️

CSRF Protection

Standard forms and authenticated API requests require a valid CSRF token. This prevents malicious websites from performing actions on your behalf if you happen to visit them while logged in. Token-authenticated endpoints (e.g. webhooks) use their own verification.

Implementation: Flask-WTF CSRFProtect on POST/PUT/PATCH/DELETE for authenticated forms. Token-authenticated integrations use separate verification.
📋

Audit Logging

Security-relevant and key account actions are recorded in an append-only audit log with a 7-year archival policy. This supports GDPR subject access requests and regulatory compliance.

Retention: 7-year archival policy. Logs include user, IP, action, timestamp, and outcome.
🤖

Bot & Spam Prevention

Registration and sensitive forms employ honeypot fields, timing analysis, and disposable email detection to prevent automated abuse without degrading the user experience.

Methods: Honeypot fields, submission timing checks, disposable email domain blocking.
📡

PII-Scrubbed Monitoring

Errors and slow requests are forwarded to Sentry so we can catch regressions before they spread. A redaction layer runs on every event before transmission: request bodies on plan, account and auth endpoints are stripped, query strings on token-bearing routes are dropped, cookies and authorisation headers are removed, and any field whose name matches our sensitive-key list (password, email, date of birth, NI number, account/sort code, plan-data dictionaries, balances, holdings, goals, etc.) is replaced with [Filtered]. Only stack traces, route names and timing data leave the server. Browser-sent Content-Security-Policy violation reports are received in-house — query strings and fragments are stripped from every URL field before the report is grouped on our internal reliability dashboard, so the policy can be tightened without leaking what page a user was on when the violation fired.

Implementation: Sentry SDK with send_default_pii=False and a custom before_send scrubber in services/observability.py. Health-check transactions are excluded from sampling. CSP violations are persisted via the in-house /csp-report sink (typed config in services/csp_config.py) and surfaced on the operator reliability dashboard.

Input Validation

Every piece of data is validated before it enters the system

Allowed-Key Whitelisting

API endpoints only accept recognised field names. Unknown keys are rejected before processing, preventing injection of unexpected data into your financial plan.

Implementation: Server-side allowed-key sets on all data-accepting endpoints. Unrecognised fields return validation errors.
🔢

Type & Range Checks

Financial values are validated for correct types (numbers, dates, percentages) and sensible ranges. This prevents corrupt data from entering calculations and producing misleading projections.

Implementation: Server-side type coercion, range validation, and length limits on all user-submitted data.
🧹

Output Escaping

User-generated text is escaped before rendering to prevent cross-site scripting (XSS) attacks. Template output is auto-escaped by default, and server-side sanitisation removes dangerous markup.

Implementation: Jinja2 auto-escaping enabled by default. Server-side HTML sanitisation on user-supplied content.

Payments & Privacy

Your money and your data handled with care

💳

Stripe Payments

All payment processing is handled by Stripe, a PCI-DSS Level 1 certified provider. Your card number, CVV, and billing details are submitted directly to Stripe — they never touch our servers. We only receive a confirmation token.

Provider: Stripe (PCI-DSS Level 1). Zero card data stored on Wealth365 servers.
🇬🇧

UK GDPR Compliance

We comply with the UK General Data Protection Regulation. Your data is processed lawfully, minimised to what is necessary, and you can request access, correction, or deletion at any time. See our Privacy Policy for full details on data handling.

Rights: Access, rectification, erasure, portability. Contact: contact@wealth365.co.uk

Where Your Data Lives

Honest disclosure about hosting location and cross-border data protections

🇺🇸

Hosting Region

Wealth365's production application and database are currently hosted on Replit, Inc. infrastructure in their North America region (United States). Your account data and financial planning information are stored and processed in the US, with the UK→US transfer covered by the Article 46 safeguard described in the next card.

Development environments also run in Replit's North America region (a Replit platform constraint). Development environments must never contain real client data.

Planned future migration: moving production to Replit's European Union region is a planned future objective. Until that migration is complete, the position above is the current and authoritative one.

Provider: Replit, Inc. — North America region (production). Replit, Inc. is incorporated in the United States.
📜

Transfer Mechanism

The transfer of personal data from the UK to Replit's US infrastructure is governed by the UK Addendum to the EU Standard Contractual Clauses / UK International Data Transfer Agreement (IDTA) under our Data Processing Agreement, as approved by the ICO under Article 46 UK GDPR. The IDTA requires Replit to protect your data to a standard equivalent to UK GDPR.

Legal basis: UK IDTA / UK Addendum to EU SCCs (Article 46 UK GDPR) for the primary UK→US hosting flow. Copy on request: dpo@wealth365.co.uk.
🔒

Technical Mitigations

On top of the contractual and adequacy-based protections, these technical measures reduce the risk of unauthorised access to your data in transit or at rest:

  • TLS encryption for all data in transit
  • Fernet field-level encryption at rest (AES-128-CBC + HMAC-SHA256)
  • bcrypt one-way password hashing — we cannot recover your password
  • Sentry error monitoring (US) with PII scrubbed before transmission
📋

Your Rights

Your UK GDPR rights include the right to ask us for a copy of the safeguards that govern any transfer of your data outside the UK, the right to request that processing be restricted, and the right to ask us to delete your data.

Full detail: See Privacy Policy Section 7 (International Transfers). Contact: dpo@wealth365.co.uk

Backup & Disaster Recovery

How quickly we can recover your data, and how often we prove the recovery actually works

Provisioning in progress (May 2026): the off-platform backup destination has been chosen — Hetzner Object Storage (EU) — and the full scheduling, monitoring, restore-rehearsal, and alerting pipeline is implemented and ready. Operator provisioning (bucket creation, GPG key import, and secret wiring) is in progress; our internal reliability dashboard will report unconfigured until those steps are completed and signed off. The Recovery Objectives below are the targets we will meet once the pipeline is live. In the meantime, the platform continues to rely on our hosting provider's managed PostgreSQL snapshots (point-in-time recovery within the provider's blast radius).
💾

Daily Off-Platform Backups (provisioning in progress)

The backup pipeline takes a full logical backup of the production PostgreSQL database each night with pg_dump, encrypts it with a recipient-only GPG public key, and uploads it to Hetzner Object Storage in the EU region. Backups are stored outside our primary hosting provider's blast radius, so a provider-level incident cannot destroy both the live database and its only copy.

Target cadence: nightly at 02:00 UTC. Encryption: GPG public-key — only the offline recipient private key can decrypt. Target retention: 30 days. Chosen provider: Hetzner Online GmbH, EU region (EEA). Active once operator provisioning is complete.
🎯

Recovery Objectives

We publish concrete, operator-committed targets for how much data could be lost and how long a full recovery would take. These are the numbers our internal reliability dashboard tracks against once off-platform backups are wired up — not aspirational figures.

  • RPO (Recovery Point Objective): 24 hours — measured from the most recent successful off-platform backup once that pipeline is live.
  • RTO (Recovery Time Objective): 4 hours — full restore-from-scratch including standing up a fresh app instance, pg_restore, and the smoke-test pass described in our internal DR runbook.
🧪

Weekly Restore Rehearsals (provisioning in progress)

The implemented rehearsal downloads the most recent encrypted backup from Hetzner, decrypts it, and restores it into an isolated scratch database. It runs row-count sanity checks against every table the live application declares, confirms the Alembic schema head in the restored copy matches the deployed application, and decrypts a sample of Fernet-encrypted fields to prove the current encryption key still works against the backup ciphertext. If the rehearsal does not succeed at least once per 8 days, the dashboard tile flips to "Rehearsal overdue" and the on-call operator is paged.

Target cadence: weekly on Mondays (UTC). Verification: TOC parse, scratch pg_restore, row-count windows, Alembic head match, and Fernet decrypt of sampled encrypted fields. Active once operator provisioning is complete.
🔑

Key Custody & Rotation

The FIELD_ENCRYPTION_KEY that protects Fernet-encrypted fields at rest is stored in Replit Secrets, never in source control, never in logs, and never in Sentry events. Access is restricted to named operations engineers. The application refuses to boot if the key is missing or fails its entropy check. The backup GPG keypair's private half is held offline (never in the production environment) by the same restricted access list, so a compromise of the Hetzner bucket alone cannot yield readable data — the offline private key is always required.

Storage: Replit Secrets (production). Backup key: GPG private key held offline by named custodians only; public key only is in the production keyring. Rotation: Procedure documented in our internal DR runbook.

Calculation Accuracy

Our tax engine is continuously verified against HMRC rules

Automated Test Suite

Every calculation in our tax engine — income tax, National Insurance, capital gains, dividends, pension allowances, and more — is verified by an automated test suite that runs against known UK tax rules and HMRC thresholds.

Checking tests...
📊

What We Test

Our test suite covers the areas that matter most for your financial plan:

  • UK income tax bands and personal allowance taper
  • National Insurance thresholds and rates
  • Dividend and savings income taxation
  • Capital gains tax with annual exemption
  • Pension tax-free lump sum calculations
  • ISA growth projections and contribution caps
  • The 60% marginal rate trap (£100k–£125,140)

Responsible Disclosure

If you discover a security vulnerability, we encourage responsible disclosure. Please report it to security@wealth365.co.uk. We appreciate researchers who give us the opportunity to address issues before public disclosure.

Our security.txt file follows RFC 9116 standards for security contact information.

Ready to Start Planning Securely?

Your financial future, protected by real security measures. Not just promises.

Start Your Free Trial