> For the complete documentation index, see [llms.txt](https://docs.madhousewallet.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.madhousewallet.com/security/gnosis-safe.md).

# Encryption & Key Management

AES-256-GCM encryption and AWS KMS key management

***

## Data at Rest

All sensitive data stored by the platform is encrypted using **AES-256-GCM**:

* API response payloads for dashboard sessions are encrypted end-to-end with a per-session derived key
* Session keys are derived as `HMAC-SHA256(masterKey, userId:sessionId)` — each session gets a unique key
* Rotating the master encryption key immediately invalidates all active sessions

## Data in Transit

All API traffic uses **TLS 1.2+**. There are no unencrypted endpoints.

Incoming webhooks (from payment networks) are verified using **RSA-SHA256** signature validation against published public keys. Requests with missing or invalid signatures are rejected and logged.

***

## API Key Storage

API keys are never stored in plaintext. Only the SHA-256 hash of each key is persisted in MongoDB:

* **SHA-256** is appropriate here (not bcrypt) because 128-bit entropy makes brute-force infeasible and enables fast O(1) indexed lookups
* The full key is shown once at creation via the dashboard and is not recoverable afterward
* Revocation is instant — deleting the hash record immediately blocks all requests using that key

***

## Signing Keys (AWS KMS)

On-chain signing operations (ERC-4337 UserOps, Safe transactions) use **AWS KMS** with secp256k1 key material:

* The private key is generated inside and never leaves the KMS HSM
* All signing requests call `kms.sign()` — the plaintext key is never in application memory
* The IAM role requires only `kms:Sign` and `kms:GetPublicKey` — no export permissions
* DER-encoded ECDSA signatures are normalized (low-S) for EVM compatibility

***

## WebAuthn Passkey Authentication

Dashboard users authenticate using **WebAuthn passkeys** (device biometrics or hardware security keys):

* No passwords stored anywhere in the system
* Private keys are generated and stored by the device's secure enclave
* The server verifies assertions using `@simplewebauthn/server` — the private key never leaves the device
* Signature counters are checked on every login to detect cloned authenticators

For high-value actions (initiating a transfer from the dashboard), a second passkey ceremony is required — generating cryptographic proof that the user physically authorized the specific action.

***

## Session Security

| Layer                     | Lifetime  | Purpose                                         |
| ------------------------- | --------- | ----------------------------------------------- |
| JWT access token          | 3 hours   | API credential, auto-refreshed every 30 min     |
| `mw_sess` httpOnly cookie | 7 days    | Session identity — not accessible by JavaScript |
| MongoDB UserSession       | 7 days    | Server-side revocation support                  |
| Session key (in-memory)   | Page load | AES key — never persisted to disk               |

Deleting a `UserSession` record from MongoDB immediately invalidates all tokens for that session, even within the 3-hour JWT lifetime.
