Case Study — Mobile Banking QRIS Module (Inbound & Outbound)
One static QR print = permanent merchant account hijack. We swapped the NMID before the cashier noticed.
Client Context
State-owned bank — QRIS CPM/MPM in mobile banking (Android/iOS, 4M users) — QR generation, merchant settlement & refund APIs. Pre-launch OJK & BI QRIS audit + app store release in 4 weeks.
Challenge
QRIS flows mix mobile SDK, backend APIs & merchant settlement — attacker window: QR tamper, MITM on public Wi-Fi, and merchant spoof. Prior SAR: hard-coded SDK key in app.
Scope — Snipeyes Mobile + API Pen-Test (CREST, MASVS)
- iOS/Android static + dynamic analysis: OWASP MASVS L2, hard-coded secrets, SSL pinning, root/jailbreak, intent leakage
- QR lifecycle: MPM static print, CPM dynamic token (30s), settlement
callback&refund— tamper, replay, race condition, amount swap - Backend APIs (19 endpoints): BOLA, IDOR on
merchantId/NMID, signature bypass, rate-limit on QR gen - Settlement & reconciliation: merchant spoof, double-credit, webhook forge
Key Findings (redacted)
- CRITICAL: Static MPM QR —
NMID+merchant PANnot signed → attacker reprinted QR with own NMID, funds diverted (PoC: sticker overlay) - HIGH: SDK
API_KEYhard-coded + no pinning → MITM on public Wi-Fi allowed QR payload tamper (amount 10k → 1M) - HIGH:
refundBOLA — any merchant could refund other merchant’s transaction via IDOR - 22 findings: 1 Critical, 3 High, 8 Medium, 10 Low — CVSS + MASVS/PCI DSS 4.0 mapping, retest included
Outcome
- Dynamic QR now signed (HMAC) + short-lived, SDK key moved to vault + cert pinning + RASP — retest 100% critical closed in 5 days
- Passed BI QRIS & OJK audit first submission, app store approved, fraud rate 0 on launch month
- Merchant QR re-issuance SOP + settlement anomaly rule (Snipeyes Fraud Detection hook)
Relevance for you: If you run QRIS, wallet or merchant acquiring — we test the print, the app, and the settlement, not just the API.