--- title: Security, legal & operational risks description: Compliance frame (ToS, PJP/BI licensing, gray zones), account-suspension evidence, credential-handling audit across the three repos, operational failure modes, and practical hygiene for anyone touching this space. status: concluded category: technical tags: [gopay, gobiz, risk, tos, compliance, credentials, security] draft: true created: 2026-10-15 updated: 2026-10-15 --- # Security, legal & operational risks > Part of [[gopay-merchant-qris-gateway/index|GoPay Merchant QRIS gateways]] ## 1. The compliance frame - **What these tools do is not itself payment processing.** They automate a merchant's own account: render a QR from their own static QRIS, and read their own transaction feed. Funds settle through normal QRIS rails to the merchant's own balance. No third party touches money. [verified — mechanism, see [[gopay-merchant-qris-gateway/analysis|analysis]]] - **But it is not a sanctioned integration either.** All three repos are explicit: unofficial, not affiliated with GoTo/GoPay/GoBiz, "may violate providers' Terms of Service". Automated access to the private portal API — replaying a browser session with a spoofed fingerprint — is the kind of use ToS clauses exist for. [verified — repo disclaimers S1][S2][S3; S11] - **Regulated edges [inference, legal framing]:** In Indonesia, QRIS acceptance is Bank Indonesia-regulated, and *providing payment services to third parties* requires a PJP license. A merchant automating their own acceptance is a gray zone of *consumer/micro-merchant self-service*; pointing the same mechanism at **other people's transactions** (aggregating sub-merchants through one account) would clearly cross into regulated activity. Nothing in the audited code prevents that misuse, and nothing in the repos encourages it. - **Data-protection angle:** session tokens are account credentials; a leaked session exposes transaction data, balances, and (per the app-side endpoint map) payout surfaces. Handling rules therefore match credential handling — see §3. ## 2. Account-action risk (what actually breaks accounts) Evidence from the ecosystem's own comms [reported — no GoPay statement available]: - Maintainer of `gobiz-payment`, in issue #3, on suspensions: users report suspension/limitation correlated both with **aggressive polling** and with **rapid transaction growth** ("masa usaha mulai laris malah di suspend karena alasan terjadi peningkatan transaksi" — account suspended for a transaction spike). [S4] - Community-adopted mitigation, endorsed in that thread and implemented by QMID: **poll only while a checkout is active** ("on-demand poller" → idle traffic 0), keep the ~6 s interval, one poller per account, no parallel watchers. [S4][S6 §2.3] - Observed server-side rate limit on the login/OTP request: 10/min. [S7] - Open field reports: OTP not arriving (#7), empty history (#4) — both likelier account-state/drift than protocol death. [S14] - Aggravating factor [inference]: all three designs funnel an entire business through **one** merchant session; any account action stalls all automation, and every re-login re-sends OTPs (higher exposure) if refresh tokens aren't used. ## 3. Credential-handling audit (repo by repo) | Repo | What it stores / collects | Audit verdict | |---|---|---| | `gopay-api-gateaway` | Phone number + OTP entered at CLI; session written to `.GOPAY_SESI_JANGAN_DIHAPUS.json`; tokens used by `server.js` | **Cannot be audited**: `login.js` + `sessionManager.js` are obfuscated (no readable strings). Self-hosted, so credentials stay on your server *if the obfuscated code is honest* — that "if" is the entire problem. Also: checkout page sends the QR payload to third-party `api.qrserver.com`. [S3] | | `gobiz-payment` | Phone+OTP or email+password from `.env`; tokens in `.gopay_cache.json` | Readable; auth calls run through the system `curl` binary (odd but transparent — no hidden network calls). Tokens stored **plaintext on disk** (README says gitignore). [S2] | | `QrisMerchantID` | Same model, plus HAR files kept outside the repo | Readable; explicit hygiene rules: HARs contain live credentials → gitignored, never committed, values masked in reports ("4 leading + 4 trailing chars"); token cache API with documented save/load. [S7][S11] | **[verified] Common pattern:** all three store session tokens in a plaintext file next to the app and remind users to gitignore it. No encryption at rest anywhere; no keyring. Treat every such file as a live credential. **The obfuscation red flag, stated precisely:** the most popular repo hides exactly its credential-handling code (see [[gopay-merchant-qris-gateway/repos|repos]] §1). This is not an accusation of malice — but for a tool that asks for an SMS OTP with full account access, "trust us, it's obfuscated" inverts the property an auditable client should have. The README's "your data stays 100 % on your own server" is only verifiable modulo the hidden code. [inference] ## 4. Operational failure modes (verified in code / reports) - **Drift kills silently** — version-gated endpoints can degrade into unhelpful errors; the literature's whole drift playbook exists because clients break when the portal moves. [S7][S13] - **Claim state in RAM** (`gopay-api-gateway`) — restart within 24 h → previously claimed transactions can be claimable again; multi-instance compounds it. [S3] - **Refresh fragility** — expired refresh token → forced re-login → OTP cycle; QMID disables polling on rejection (fail-fast), kavionn has no refresh path at all. [S10][S2] - **Third-party dependency in the hot path** — QR images rendered via an external service in the gateway; offline/blocked → checkout breaks. [S3] - **No delivery guarantees** — confirmation is pull-based (store polls the tool; the tool polls GoPay). If the store backend misses the confirmation window, orders lapse with money received; no retry/alarm semantics beyond the watcher timeout. [inference from architecture] - **Unit-scale bugs are lurking** — see the cross-repo discrepancy in [[gopay-merchant-qris-gateway/analysis|analysis]] §4: a 100× mismatch class of bug is easy to ship and hard to notice in tests (both 25000 vs 2500000 look like plausible amounts). ## 5. Who this is exposed to (risk surface, neutral) - **The merchant running it:** account suspension/ToS action (real evidence above); credential custody (obfuscated clients; plaintext caches); business continuity on a single session. - **Buyers:** none directly — no funds route through the tool; QRIS is a push payment via the buyer's app; the checkout page exposes no buyer data beyond what the buyer types nowhere (page is static + polling). [inference from code] - **The payment ecosystem:** the load pattern (replayed portal sessions, spoofed browser fingerprints) imposes automation on a consumer-facing control plane; at scale this is indistinguishable from credential-stuffing/scapegoat traffic for anti-fraud systems, and may drive friction for legitimate users. [inference] - **Misuse vector to note:** stolen GoPay merchant session tokens become immediately useful (read balances, explore payout endpoints documented in the APK map). The tooling itself adds no new auth weaknesses — it *is* the demonstration that web-session tokens are the crown jewels of this ecosystem. [S8][inference] ## 6. Disposition of the research itself The QrisMerchantID project published a **responsible-disclosure doc** covering its APK findings (static indicators only, 0 critical, secret masking, no re-distribution of APKs, vendor contact channel, 7-day correction policy) and holds `0 critical` as its verdict. [verified — S11]. Its stated non-negotiables — no backend probing, no credential tests, no publishing raw secrets, no "vulnerability" claims from static indicators — match what this audit observed in the artifacts. [S9 §5] ## 7. Practical hygiene (if you touch this space) 1. **Read the code first** — prefer readable implementations; treat obfuscated auth code as unauditable and avoid it for real credentials. 2. **Own account only** — the entire method is "your account, your traffic". Anything else is account takeover territory. 3. **Sessions are crown jewels** — plaintext caches + `.env` + HAR files: gitignore, exclude from backups/syncs, rotate after any exposure. 4. **Poll like a human would** — only during active checkouts, ~6 s floor, one poller per account. 5. **Expect breakage as a feature of the category** — budget for drift maintenance; don't build revenue-critical flows without a fallback (manual reconciliation is the fallback these tools automate away). 6. **For production/compliance-grade needs, the official route is a licensed PJP gateway** (Midtrans/Xendit/DOKU etc.) — that's the option these tools exist to avoid, and their entire risk profile is the price difference. Both the platforms' ToS and BI's licensing regime are the boundary of what *should* be built here; this vault records how the ecosystem works, not an endorsement of deploying it. [inference]