Skip to main content
Woku uses two cryptographic primitives to protect the data it stores in its database:
  • AES-256-GCM encryption for sensitive fields at rest.
  • HMAC-SHA256 to sign critical documents and detect any later modification.
Both primitives live in a single EncryptionService on the backend and use the same master key (ENCRYPTION_KEY) derived via scrypt.

Encryption at rest

When encryption happens

Every field that contains personal information or credentials is encrypted before being persisted in MongoDB. In particular:
  • Client data in anonymous responses: email and phone are stored encrypted (form-submission).
  • Integration credentials and OAuth tokens (when a company connects Woku with Salesforce, Sperant, etc.).
  • Webhook secrets that the company configures to receive events.

How it works

Each encryption uses a new IV, so encrypting the same value twice produces two different ciphertexts (equality cannot be inferred by inspection). The authTag is validated on every decryption: if the ciphertext was altered, decryption throws an error instead of returning garbage.

Search over encrypted fields

To be able to search by email without decrypting every record, Woku stores a parallel SHA-256 hash (generateSearchHash) in lowercase. The search compares hash against hash, not text against text.

Integrity signatures (HMAC-SHA256)

What they are for

When a company requires that its form responses cannot be modified after being stored (legal auditing, compliance in a regulated sector), Woku can sign each document with HMAC-SHA256 at write time and verify the signature when reading it. If someone modifies the document in the database directly, verification fails and the read returns an error.

How it works

Scope = domain separation: each use case signs with a different scope (e.g.: form-submission, form-response). A signature generated for one scope is not valid in another, so an attacker cannot move signatures between document types. Canonical JSON: Woku recursively sorts the keys of the objects before signing, so two logically equal representations of the same document produce the same signature (regardless of the order in which the API received them or Mongo wrote them). Arrays are NOT reordered, positional order is semantically significant.

Enable it for your company

There is a per-company flag: integrityHashEnabled. When it is enabled, new writes of critical documents are signed; reads verify and fail if the signature does not match.
Current status: the primitive (signDocument / verifySignature) is already available on the backend and the flag exists in the company model. Automatic integration with form-submission and form-response (when integrityHashEnabled is active) arrives in a later release. Customers with strict compliance who need this sooner can coordinate it with support.

Key management

  • ENCRYPTION_KEY lives in SSM Parameter Store as a SecureString under /shared/prod/secrets/ENCRYPTION_KEY and is injected into the container at startup (see Secrets management).
  • Key rotation is manual today. It involves:
    1. Generating the new key.
    2. Re-encrypting all records (migration script) with the new key before switching ENCRYPTION_KEY in SSM, during a maintenance window.
    3. Discarding the old one.
  • There is no HSM in V1; the key lives in the process environment variables (in memory) and is never logged.

Guarantees

  • Authenticated encryption: if an attacker modifies the ciphertext in the database, the authTag does not validate and decryption throws an error, so the altered record is not returned as if it were valid.
  • Constant-time signature: verifySignature uses comparison resistant to timing attacks.
  • Domain separation: the scope in HMAC prevents reuse of signatures between document types.
  • Deterministic JSON: canonicalization removes ambiguity from key order.

Known limitations

  • Rotating ENCRYPTION_KEY requires a maintenance window (there is no key versioning yet).
  • Signing of form-submission / form-response is not wired automatically; it arrives in the Stage 10 release.
  • Applying it to third-party integration credentials depends on those integrations being built (Stage 6).