The threat model
Each threat has at least one defence. Most have two.The five guarantees
The promises Guild makes about security, in order of importance.1. No webhook can credit a wallet on its own
Detail: Webhook verification. Every OPay webhook passes three checks before any wallet motion: HMAC-SHA512 signature verification, idempotency check on the event ID, and re-verification against OPay’s authoritative endpoint. Even if the webhook secret leaks, a forged webhook cannot fake a successful transaction — because we ask OPay to confirm.2. PII never sits plaintext on disk
Detail: KYC tiers & data residency. BVN, NIN, last name, date of birth, gender, full address — all envelope-encrypted with XChaCha20-Poly1305 before being written. The master key lives in the host’s environment, not in the database. The AAD (additional authenticated data) is bound to the user’s ULID, so a swapped ciphertext blob fails to decrypt. A database leak alone yields ciphertext with no key.3. Audit history is structurally immutable
Detail: Append-only audit ledger.channel_audit and payments_audit tables have BEFORE UPDATE OR DELETE triggers that reject mutation. Once a row is inserted, it’s permanent. Not editable by application code, not editable by an engineer in a psql session, not editable by anyone short of dropping the trigger (an action that is itself logged and reviewed).
4. Every internal call is cryptographically signed
Detail: Inter-service communication.@guild/svc-client signs every service-to-service request with HMAC-SHA256 over (method, path, body, timestamp, nonce, actor). A 300-second skew window plus a nonce cache (Redis, 10-minute TTL) prevents replay. crypto.timingSafeEqual for every comparison.
5. Partner access is consent-gated, scoped, and revocable in real time
Detail: Partner consent. Every snapshot read by a partner requires an active consent record on Guild’s side. The consent specifies the scopes the partner can see and an expiry date. The user can revoke at any time from their dashboard; the next snapshot fetch with that consent ID will fail withconsent_revoked.
Defence-in-depth principles
The architecture follows three rules.Assume every secret can leak
We don’t design the system to depend on a single secret staying secret. The webhook reconcile guard makes OPay’s authoritative endpoint the source of truth even if our webhook secret leaks. The envelope encryption makes the master key matter even if the database leaks. The session ULID is opaque, so even if a cookie leaks, it conveys no information.Defence in depth, not defence by exception
We don’t allow “trusted” callers to bypass any check. The signed-request middleware applies to all inter-service traffic uniformly. The reconcile guard runs on every OPay webhook, not just the ones we’re suspicious of. Uniformity beats exception-list maintenance.Make security checks part of the type system
Where possible, security checks are encoded in types, not just runtime checks. A wallet credit operation cannot be invoked without a verified webhook reference. A KYC-encrypted field cannot be read without the decryption helper. The compiler stops us from making certain classes of mistake at edit time.Compliance posture
NDPR alignment
Nigeria Data Protection Regulation is the relevant compliance baseline. Our posture:- Consent. Explicit, granular, revocable. Logged in the audit ledger.
- Data minimisation. We collect only what’s needed for the platform’s stated purposes (matching, payments, KYC, standing).
- Right to erasure. A user who deletes their account triggers anonymisation of personal identifiers. The audit rows persist (required for transaction reconstruction and partner contracts) with an anonymised user ID.
- Right to portability. Data export endpoint in the user dashboard. The user gets a signed JSON archive of their data.
- Lawful basis for processing. Consent for marketing and analytics; legitimate interest for transactional processing; legal obligation for AML/KYC.
Data residency
Hosting is on virtual private servers. Backup snapshots replicate cross-region within the provider. We do not export user data to third parties outside the consent boundary.BVN / NIN handling
Verification through licensed providers. The BVN and NIN themselves are envelope-encrypted; the application code reads them only when verifying or when explicitly displaying to the user. Application logs redact them. They never leave our control for any purpose other than the verified-once handshake.Penetration testing and reviews
A short list of operational practices:- Quarterly internal security review of the codebase, signature implementations, and secret handling.
- Annual third-party penetration test of the public surface (Partner API, BFF endpoints, webhook receivers).
- Pre-launch bug bounty before significant feature releases that change the auth surface.
- Continuous dependency scanning (
pnpm audit, GitHub Dependabot) with automatic PR creation for security patches.
What we don’t claim
Honesty about scope:- We are not a SOC 2-certified system at v1. Working toward it as the platform matures. We follow SOC 2 principles in operation; certification is a process.
- We do not encrypt every column. Non-sensitive fields (timestamps, status enums, references) sit plaintext. Only the columns containing PII or financial-account identifiers are encrypted.
- We do not run multi-region failover today. Backup replication is cross-region; live failover is a known operational task at higher scale.
Where to go next
Webhook verification
The full signature spec for OPay, WhatsApp, voice, and Partner webhooks.
Audit ledger
The append-only contract and what it means in practice.
KYC tiers
Tier 1, 2, 3 — what’s verified at each step, what’s encrypted, how data flows.
NDPR posture
The compliance framing in detail.