Technical Due Diligence · June 2026

XOX eWallet
Technical Analysis

A full-stack assessment of the existing eWallet codebase — covering current architecture, technical findings, and a proposed roadmap for v2.0. Prepared by Fast Technology Sdn Bhd.

5 Critical Issues 10 Medium Issues DuitNow / NPG Live BNM Licensed
Part 01
Current Architecture
As-built system map based on full codebase review. ~10,000 files across Django backend, React Native mobile app, and PHP back-office portal.
CLIENT LAYER API LAYER DATA LAYER Mobile App React Native Expo · JavaScript Consumer + Merchant 466 files Back-Office PHPRunner Low-code generated Ops · Finance · KYC ~300 PHP files HTTPS Django 3.2 REST API Python 3.6 · EOL Dec 2021 accounts/ Users · Wallets · KYC transactions/ Money logic · DuitNow otps/ Step-up auth bw/ Bank-wallet (MPP) reload/ Top-up logs/ Audit trail webapi/ Public endpoints MySQL Single database Mutable balance model No ledger pattern EXTERNAL DuitNow NPG Zoloz eKYC JWT Auth
What works well
JWT authentication (5-min access / 15-day refresh with blacklist). Atomic transactions + select_for_update on DuitNow flows. PIN lockout (3 attempts → suspend). Step-up auth for large amounts. Audit trail logging. Live DuitNow / NPG / Zoloz eKYC integrations. ~1,360 commits of history. The duitnow_balance_handler.py module is well-structured with proper available_balance vs current_balance separation and daily limit aggregation.
Django Backend
3.2 / Python 3.6 · 7 apps · ~1,360 commits · Last active Nov 2025 (7 months dark). JWT + sessions. Real money logic lives here.
React Native App
Expo · JavaScript → partial TypeScript migration. 466 files. Consumer + merchant wallets. JWT stored in Redux (not secure storage).
PHPRunner Portal
~300 PHP files. Low-code generated. Ops, finance, compliance. Hardcoded credentials. Not auditable. Should be internal-network only.

Part 02
Technical Findings
15 findings from full codebase review. Severity rated: Critical (fix now) → High (fix this sprint) → Medium (fix this quarter).
5 Critical 3 High 7 Medium 1 Well Done
# Area Finding Severity
1 Security .env, privatekey.pem, and privatekey_pkcs8.pem are committed and tracked in git. Anyone with repo access has the wallet signing keys. CRITICAL
2 Security DB credentials, SMTP password, and JWT secret hardcoded in PHP portal source code. CRITICAL
3 Runtime Python 3.6.15 — EOL December 2021. Zero security patches available. Every known Python vuln since 2021 is unpatched. CRITICAL
4 Security pycrypto 2.6.1 in requirements — abandoned crypto library with known CVEs. pycryptodome (the maintained fork) is already present, so this is just dead weight + open CVEs. CRITICAL
5 Testing Only accounts/tests.py has ~31 lines of tests. Every other app is an empty stub. Zero test coverage on balance and transaction logic — changes cannot be safely made. CRITICAL
6 Money Model wallet.current_balance is overwritten on every transaction. Confirmed: payer_post_balance = payer_wallet.current_balance - amount. If a crash occurs mid-transaction, balance drifts permanently with no way to reconstruct from first principles. HIGH
7 Security OTP stored as plaintext char field in trx_otp table. Should be hashed. HIGH
8 Mobile JWT tokens stored in Redux state (in-memory). Should be in Keychain (iOS) / Keystore (Android) — OS-level secure storage. HIGH
9 Code Quality NPG gateway logic (npgsenddata.py) duplicated across 4 apps: bw/ (502 lines), transactions/ (275), reload/ (116), webapi/ (27). All have diverged. A bug fix must be applied 4 times or the system is inconsistent. MEDIUM
10 Code Quality duitnow_views.py = 2,575 lines. accounts/register.py = 911 lines. God files — untestable and unmaintainable. MEDIUM
11 Data profile_pic stored as BinaryField in the main user table. Profile images in the transaction DB inflate row size and slow all user queries. MEDIUM
12 Platform Django 3.2 extended support ended April 2024. Most pip dependencies are several years old with published advisories. MEDIUM
13 Mobile Partial TypeScript migration — newer screens are .tsx, legacy are .js/.jsx. Referenced type definitions removed. Type errors fail silently in production builds. MEDIUM
14 Mobile Debug console.log statements throughout mobile codebase — leaking transaction state and user data to device logs in production. MEDIUM
15 Ops # KENA SET BALIK ALL SETTINGS comment in config/settings/prod.py line 13 — evidence of manual config drift between dev and prod environments. MEDIUM
One thing done right: duitnow_balance_handler.py
This is the newest, best-written module in the codebase. It uses proper available_balance vs current_balance separation (hold pattern), atomic transactions with select_for_update, daily limit aggregation inclusive of pending states, and min/max guards. Whoever authored this module understood financial system design. This person is the key technical asset Fast Tech needs to identify and engage.

Part 03
eWallet 2.0 — What to Build
Six core changes that must happen, plus the recommended tech stack and delivery phases. Total timeline: 11–17 months with a dedicated team.
1 Double-Entry Ledger
Current mutable balance can drift permanently. Every transaction in 2.0 must produce 2 immutable entries (debit + credit). Balance is derived by summing entries — never written directly. Store as integer sen (1234 = RM12.34). No floats. This is the foundational change that everything else depends on.
2 Secrets Out of Code
Signing keys are compromised right now. Immediate: rotate all keys and remove from git history. Long-term: all secrets via Vault or AWS Secrets Manager. HSM for signing keys — they never leave the HSM. CI secret scanner (gitleaks) blocks any future credential commit.
3 Upgrade Runtime
Python 3.6 has had zero security patches since Dec 2021. Upgrade path: Python 3.11 → Django 4.2 LTS → audit all dependencies with pip-audit. This is a prerequisite for anything else — running on EOL software makes every other security effort moot.
4 Test Coverage on Money Logic
Zero coverage means no change can be made safely. Unit tests required: balance arithmetic, transaction state machine, freeze/deduct/return cycle, negative balance guards, daily limit enforcement. These run on every PR via CI — no merge without green tests.
5 Single Payment Module
NPG gateway logic exists in 4 diverged copies. Extract into one payment_gateway/ service. All apps call it. One bug fix propagates everywhere instead of being applied 4 times (or missed in 3 copies). Same pattern for DuitNow callbacks.
6 Replace PHPRunner Portal
Hardcoded credentials, low-code generated, not auditable. Replace with React + TypeScript admin portal. RBAC, maker-checker on all money actions, full audit view. Uses the same APIs as the mobile app — no separate backend surface.
Recommended Tech Stack
Layer Choice Rationale
API Core Python 3.11 + FastAPI Preserves team velocity. Async-native. Ledger discipline is language-agnostic — the data model matters more than the language. Django 4.2 is valid fallback.
Database PostgreSQL Real NUMERIC, strong constraints, exclusion constraints, logical replication. MySQL has documented floating-point edge cases for financial arithmetic.
Cache / Locks Redis Hot balance reads, rate limiting, distributed locks for concurrent wallet operations, idempotency key cache.
Events Kafka or AWS SQS Outbox pattern — events published atomically with ledger writes. SQS for simpler start; Kafka when throughput demands it.
Mobile React Native + TypeScript Keep existing RN investment. Complete the TypeScript migration fully. Tokens move to Keychain/Keystore.
Back-Office React + TypeScript Replace PHPRunner permanently. Same stack as mobile team — no context switch. RBAC and maker-checker built in from day one.
Secrets AWS Secrets Manager Never in code, never in env files tracked by git. Rotate without redeployment. HSM for signing keys.
Observability OpenTelemetry + Grafana End-to-end tracing on every transaction. "What happened to this transaction?" answerable in seconds, not hours of log digging.
Delivery Phases
P0 Security Triage
1–2 weeks · Starts now
Rotate all committed keys. Remove from git history. Deploy secret scanner. Patch Python CVEs. Restrict PHPRunner to internal network only. Deliverable: no known active exploits.
P1 Ledger Core
2–3 months
Double-entry ledger, idempotency keys, transactional outbox, test harness (≥80% coverage on money logic). This is the foundation — every feature after this is safe to build on.
P2 Rails + Identity
2–3 months
Single payment service (DuitNow / NPG), KYC / liveness re-integration (Zoloz), risk engine and daily limits, BNM compliance reporting.
P3 New Clients
3–4 months
New React Native + TypeScript mobile app and React back-office portal at full feature parity with current system. Tokens in secure storage. Zero PHPRunner dependencies.
P4 Harden
1–2 months
Load testing, penetration test, automated reconciliation between new ledger and legacy data, formal security review. Pre-migration sign-off.
P5 Migration
2–3 months
Parallel run with shadow ledger validation. Phased user cohort cutover (5% → 25% → 100%). Legacy decommission. BNM licence stays with XOX throughout — no re-certification required.
BNM Licence — no disruption
The e-money licence stays with XOX throughout. As long as the licensed entity remains unchanged, there is no re-certification requirement. The rebuild is a backend infrastructure change, not a licence change. Fast Technology partners with XOX as the technical arm — XOX remains the regulated entity.

Next Steps
Fast Technology's Engagement Model
Three phases of engagement — from immediate security triage to long-term technical partnership.
Immediate — P0 Triage
Rotate compromised keys. Deploy secret scanner. Patch CVEs. 2 weeks, low cost. High trust signal — Fast Tech shows up with a fix, not just a proposal.
Medium Term — Tech Partner
Fast Tech becomes XOX's de facto engineering arm on retainer. Covers maintenance of existing system while P1 ledger core is built in parallel. No service gap.
Long Term — 2.0 Build
Full 2.0 rebuild on outcome-based commercial terms. Retainer baseline + milestone payments tied to phase delivery. Shared upside on cost savings and new revenue enabled by the platform.