Money

verified before credited

Access

server-side enforced

Data

encrypted end-to-end

Systems

monitored & tested

What we did with KodiiPay

We built KodiiPay with security at the product level, not as an afterthought.

How we did it

“We secured KodiiPay by locking the app with biometric and PIN protection, enforcing email OTP and device limits, preventing withdrawals without KYC approval, validating every M-Pesa callback before a credit was written, and making sure the wallet was driven by an immutable ledger instead of a simple balance field.”

“We also kept the M-Pesa PIN off the app, enforced server-side money rules, created refund and KYC-hold paths for unverified payouts, and built a system where account resets, session revocation, payments and wallet activity all followed the same security discipline.”

We did

Biometric and app lock

We made every mobile session protectable with biometric unlock, a 4-digit PIN fallback, and auto-lock timing so the app could not be opened casually from a lost or stolen device.

We did

Email OTP and account protection

We required stronger verification for sign-in, password recovery and sensitive actions so an exposed password alone was never enough to take over an account.

We did

Device and session control

We gave users direct control over device limits, active sessions and session eviction so a stale device could be logged out immediately and a new device had to be approved properly.

We did

KYC before withdrawal

We blocked withdrawals for unverified users and protected landlord payouts by holding funds until the identity and payout rules were satisfied.

We did

Money was never trusted from the client

We run money moves on the server and through database functions so the frontend never directly modifies balances, sends money or accepts a payment on faith.

We did

Daraja callback verification

We treated every STK, C2B, B2B and B2C callback as a claim that had to be validated against the real gateway response before the wallet was credited.

Security, built into everything

One product. Twelve grounded layers.

Security is not a feature added at the end of development. It is an architectural responsibility that begins before the first line of code — and it is enforced from the login screen down to the vault beneath the database.

Surface — the login screenLayer 06 — APIs & moneyLayer 12 — the vault floor
Layer 010%

Identity & authentication

Who is allowed in

Every system we build starts with one question: who should be able to enter at all? We establish strong boundaries around identity before anything else exists.

Strong password foundations

Passwords are stored using slow, salted, memory-hard hashing — never reversible. Breached-password checks block known-weak credentials at the door, and users are pushed toward passphrases, not guesses.

Multi-factor authentication

A password alone is never the final gate. One-time codes, TOTP authenticator apps, passkeys, biometrics and backup codes combine so a stolen password is not enough to get in.

Email & phone verification

Accounts verify the contact information that owns them before sensitive actions unlock. Verification links and codes are one-shot, time-limited and rate-limited against brute force.

Recovery that cannot be hijacked

Password reset and account recovery use out-of-band verification, rotating tokens and forced re-verification of the device — so recovery paths do not become takeover paths.

Sessions as temporary trust

Sessions are short-lived credentials, not permanent entitlements. Tokens expire, rotate and are re-verified for sensitive actions, keeping a long-lived session from outliving its need.

Kill switches per session

Any session can be terminated individually or everywhere at once from the account. Losing a device or forgetting a laptop never means permanent access.

Layer 029%

Authorization & access control

What each identity may do

Being logged in is not the same as being allowed. Authorization decides what each account, role, organization or service may actually touch — and it is enforced at the server, not hidden in the UI.

Least privilege everywhere

Every role, service and function runs with the narrowest permission that can do its job. Escalation is the exception, not the rule — and it is always temporary and always logged.

Server-side enforcement

Permissions are enforced in the database and on the server, never only by hiding buttons. Knowing a URL, an endpoint or an identifier grants nothing by itself.

Object-level ownership

Every record is checked against the identity and role that owns it. A user cannot read or act on another user's rows simply by changing an ID in the request.

Deny by default

New capabilities, endpoints and roles start locked and are opened deliberately. Nothing is accessible simply because nobody remembered to close it.

Role & service separation

Admin tools, user applications and server-side services each run under their own identity model with their own credentials and their own boundary.

Administrative privilege discipline

Admin accounts are not universal keys. Elevated roles require stronger authentication, guarded sessions, reviewable audit trails and, for the most sensitive operations, approval workflows.

Layer 0318%

Session & device security

Accounts across every screen

Modern software lives on phones, desktops and browsers at once. We design the relationship between accounts, sessions and devices so one weak device can be cut out without taking the account down.

Device registration & limits

Devices are registered, named and bounded. A hard device limit prevents unlimited session growth and makes a large session list itself a detection signal.

Remote logout everywhere

Users can see every active session and terminate any of them — including a device they no longer own — from any other trusted session.

App lock & biometrics

Local app locks (PIN) and biometric protection add a second gate on the device itself, so an unlocked phone does not equal an unlocked account.

Device-link verification

Pairing a new device uses a verified, time-limited link approved from an already-trusted session — WhatsApp-style, with the approving device explicitly confirming.

Re-authentication for danger zones

Changing passwords, removing devices, withdrawing money or touching admin functions requires the credentials or an OTP again — freshness is enforced where risk is highest.

Suspicious-session detection

New locations, unusual hours and impossible geography surface as warnings and additional verification steps before trust is granted.

Layer 0427%

Data protection & privacy

The information itself

Security protects information; privacy decides how respectfully it is collected and used. Data is protected across its entire lifecycle: collection, transmission, processing, storage, access, export, backup and deletion.

Data minimization

We collect what a product genuinely needs and nothing more. The safest data is the data that never needed to be collected in the first place.

Purpose & retention limits

Data is used only for the purpose it was gathered, kept only as long as that purpose requires, then deleted — with automated cleanup running behind the scenes.

Encryption in transit & at rest

Communication is encrypted end-to-end between client, server, database and integrations. Stored data, backups and export artifacts are encrypted independently of authorization.

Encrypted at the application layer

Where sensitivity demands it, data is additionally protected before it ever reaches storage — the database does not even hold plaintext for its most sensitive values.

User rights honoured

Access, correction, export and deletion requests are real operations, not promises — including immediate, irreversible account deletion when a user asks for it.

Disclosure-free failures

Errors tell users what happened and what to do next without revealing credentials, stack traces, server paths or internal plumbing.

Layer 0536%

Application security

The software itself

Web and mobile interfaces are built on the assumption that the client is adversarial. Critical decisions are made on the server; the interface only ever proposes.

Input validation on every gate

Every input — from users, APIs, admins, uploads and third parties — is validated for type, format, size and permitted values before it is ever trusted or stored.

Injection-proof by construction

Queries are parameterized, commands are never assembled from strings, and user content is stored and rendered in ways that make injection, XSS and CSRF structurally impossible.

Secure by default headers

Content-Security-Policy, HSTS, CORS, frame and MIME protections are configured deliberately — never defaulted to permissive.

Uploads handled as untrusted

Files are validated by type and size, stored privately, served via signed expiring URLs and stays impossible to enumerate — a stored file is not a public file.

Mobile trusts nothing local

The app stores minimum data locally with protection, runs business logic on the server, and treats the device as an interface rather than an authority.

No small print in errors

User-facing errors are honest and useful; diagnostic detail is written only to protected internal logs where operators can investigate.

Layer 0645%

API, integrations & webhooks

Every boundary with the outside world

Every API is an exposed surface and every integration is a trust boundary. We treat incoming requests and callbacks as hostile until proven otherwise.

Authenticated, authorized, validated

Requests carry verifiable identity, scope and ownership checks before any sensitive operation runs — guessing endpoints or identifiers earns nothing.

Rate limiting sized to the action

Payments, OTPs, logins, uploads and admin operations each carry their own limits. Automation and brute force hit a wall, while honest users never notice one.

Idempotency on every payment path

Duplicate clicks, retried requests and repeated callbacks cannot double-charge or double-credit. Every money movement is idempotent and concurrency-safe.

Callbacks independently verified

Webhooks carry signatures, nonces and expected-resource matching, and are verified against gateway state — no callback is believed on its say-so.

Replay protection

Timestamps, nonces and event identifiers make a captured request useless twice. Duplicate events are detected and neutralized, not replayed.

Integrations granted the minimum

External services get only the permissions they need, are monitored for failure and can be isolated or revoked without collateral damage.

Layer 0754%

Database security

The vault under everything

The database is a security boundary in its own right, not a storage bucket behind the app. App-level rules are never the only lines standing between a user and sensitive data.

Row-level security

Policies at the database layer restrict every query to rows the caller is allowed to see — a tenant, landlord or owner can only ever reach their own data.

Least-privilege database roles

Application roles, service roles and admin roles each hold separate credentials with precisely scoped rights. No shared superuser for everyday work.

Transaction & constraint discipline

Referential integrity, uniqueness and check constraints protect data at the source, and balance checks run inside row locks so concurrent writes cannot corrupt state.

Protected admin operations

Schema changes, migrations and administrative queries run under controlled, reviewed processes with documented approval — not ad-hoc privileged access.

Ledgers and audit tables

Wallet ledgers, payment gateway logs and action logs are append-only, immutable trails that clients can read and auditors can trust.

Encrypted and recoverable

Sensitive columns and stores are encrypted, backups are encrypted and tested for restoration — a loss to failure or compromise never becomes permanent.

Layer 0863%

Payments, money movement & fraud

Where the money actually moves

For systems that handle cash, security stops being theoretical. Every shilling that moves does so through verified gateways, guarded balances and immutable trails — and fraud is attacked structurally.

Gateway-verified only

Deposits, payouts and transfers are credited solely on confirmation from the payment gateway itself — never on a client claim, never on a callback's say-so.

Multi-layer balance protection

Pre-flight checks, atomic decrements, row locks and non-negative constraints stack so that a balance can never go negative even under race conditions.

Escrow & holds for unsafe states

Money bound for unverified recipients, expired subscriptions or pending KYC is held, refunded or released on the correct condition — never silently lost or paid out.

Callbacks idempotently confirmed

The same STK, B2B, B2C or bank event applied twice produces one result. Confirmation procedures enforce terminal states and locks.

Fraud signals at the gateway

Rate limits, velocity checks, amount sanity and recipient verification flag attack patterns before they can drain a wallet or card.

Refund & dispute paths

Failures refund the exact amount, stale transactions are cleaned and disputed movements have defined, auditable resolution paths.

Layer 0972%

Infrastructure, cloud & network

What keeps it running

The application is one part of the system. Servers, cloud accounts, containers, networking, DNS and certificates are each their own attack surface — and each gets its own boundary.

Private by default

Components that do not need the public internet are not on it. Network isolation, security groups and restricted ports keep exposure minimal and deliberate.

Encrypted everywhere

TLS everywhere, with modern certificates, strict transport security and encrypted inter-service communication — nothing crosses the network in the clear.

Hardened compute

Base images are minimal and patched, containers run non-root, and CIS-style hardening standards are applied to the systems underneath the product.

Identity-based cloud access

Servers and services authenticate to the cloud as identities with narrowly scoped roles rather than long-lived keys lying in config files.

Isolated environments

Development, staging and production are separate worlds with separate credentials, so a breach or a mistake in one cannot walk into another.

Restricted production access

Production is reached through guarded paths — bastions, short-lived credentials and audited approvals — never casually, never by default.

Layer 1081%

Secrets, configuration & supply chain

The keys to the building

Passwords, API keys, signing keys and service secrets are never embedded in code or config files. And because modern software is assembled from packages, the supply chain is part of the perimeter.

Secrets in dedicated vaults

Credentials live in secret managers and environment configuration, separated by environment, rotated on schedule and limited by role and necessity.

No secrets in source code

Empty defaults and injected secrets at deploy time — scanning guards the pipeline so a pasted key never survives a commit.

Dependency auditing

Libraries and frameworks are pinned, audited and monitored for vulnerabilities, and unnecessary packages are removed. A weakness in a dependency is a weakness in the product.

Locked, reviewable builds

Lockfiles, dependency review and software-composition analysis keep the exact tree of packages reproducible and known.

Rotated and revoked

Compromised or stale credentials are rotated immediately, and revoking one key never cascades into breaking unrelated systems.

Supply-chain trust

Package sources are verified and third-party code is treated as untrusted until proven — external never automatically means safe.

Layer 1190%

Operations: logging, monitoring & response

Seeing what is happening

Prevention is not the whole job. Systems must be able to answer what happened, when, by whom, on what, and with what result — and to notice when the answer is unusual.

Event logs with answers

Authentication events, permission changes, sensitive operations, admin actions and failures are recorded so any incident can be reconstructed exactly.

Protected logs

Logs can contain operational secrets, so they are encrypted, access-controlled and guarded as carefully as the systems they describe.

Monitoring for the signal

Repeated failed logins, abnormal API traffic, unexpected admin actions and service anomalies surface immediately instead of silently accumulating.

Alerting wired to people

Detection is useless without a response path. Alerts reach engineers on defined channels with severity triage, not a silent dashboard.

Incident response ready

Containment, eradication, recovery and post-incident review are practiced and documented — not invented in the middle of a crisis.

Failure that is controlled

Dependencies fail, requests time out, deployments go wrong. The architecture defines graceful, observable, recoverable behaviour instead of hoping it never happens.

Layer 12100%

Resilience, testing & governance

Staying standing

Security is a property the system must keep under pressure. Backups are tested, recovery is drilled, and security is continuously probed, reviewed and governed rather than audited once.

Backups that restore

Encrypted backups, retention windows and recovery procedures exist — and restoration is actually tested, because an untested backup is a hope, not a plan.

Business continuity

Outages in third parties, databases or networks are absorbed by defined paths that control, observe and recover from failure.

Continuous security testing

Authentication, authorization, API, injection, session, file, concurrency and dependency testing run continuously — plus vulnerability assessment and penetration testing on a cadence.

Governance, documented and lived

Security policies, responsibilities, threat modeling and risk registers make the discipline repeatable instead of relying on memory.

People in the loop

Teams are trained, safe-failure is encouraged and the humans operating the system are treated as part of the security architecture — the strongest and weakest layer.

Security is not the last step

It begins before the first line of code and never ends. We build security into software from the beginning — we never add it afterward.

The vault floor

Security does not stop at the backend. It does not stop at the frontend either.

It continues through identity, permissions, databases, APIs, devices, applications, files, networks, infrastructure, cloud services, third-party integrations, deployments, monitoring, backups and the people operating the system. Every component has a role. Every connection is a boundary. Every permission is deliberate. Every sensitive operation deserves verification. Every failure needs a controlled path — and every layer is part of the security architecture.

We don't build software and add security afterward — we build security into the software from the beginning.

How we did it on KodiiPay

We built the protection into the product itself.

What we did

We built KodiiPay as a live payments platform, so we designed security into the product from the beginning. We did not treat security as a final layer, a checklist, or a late-stage patch.

We secured the app, the sessions, the wallet, the KYC flow, the payment callbacks and the money movement itself. Every sensitive action was protected by server-side rules, verification layers and auditable money logic.

We did

App lock and biometric access

We protected the app with biometric verification, PIN fallback and automatic lock timing so the account could not be opened casually from a stolen phone.

We did

Email OTP and login protection

We enforced stronger login security with email OTP, failed-attempt controls and device checks so stolen passwords were not enough to access the account.

We did

Session and device control

We allowed users to set device limits, revoke sessions and approve new devices only after verification, so old or compromised devices could be removed immediately.

We did

KYC before withdrawal

We blocked withdrawals until KYC was approved and protected payouts by holding funds where identity or payout rules had not been satisfied.

We did

Money processed on the server

We processed money movement through secure server-side functions and database logic so the frontend never directly changed balances or accepted payment claims without proof.

We did

Daraja callback verification

We treated every M-Pesa callback as a claim to be verified, not a signal to trust. The wallet was credited only after the callback was validated and reconciled.

We did

Wallet integrity

We kept wallet balances tied to an immutable ledger so every credit, debit, fee and refund could be traced, reconciled and verified.

We did

No M-Pesa PIN in the app

We never stored or handled the customer's M-Pesa PIN inside the app. The customer entered it through the official Safaricom flow on their device.

Why this matters for your build

Most software companies describe security in buzzwords. We describe it in specific engineering — because it is the engineering that protects your users, your money and your reputation.

When we build for you, you get exactly these systems: verified payments, database-enforced permissions, replay-safe integrations, secure identity flows, rate limiting, observability and tested recovery paths. Not the same ideas — the same code and practices.

The same principles we apply to KodiiPay and our own product platforms are the same standards we bring to your build.

Ask us anything

  • Is my data encrypted at rest and in transit?
  • What happens to money if a payment fails halfway?
  • How do you stop someone withdrawing someone else's balance?
  • Can you read our users' chats?
  • What happens to my data if I delete my account?
  • How are third-party APIs and callbacks verified before actions run?
Get a straight answer

Building something that handles money?

We've hardened these exact systems under real load. Let's talk about your threat model — before and after you write a line of code.