nigig-org/PAYMENT_RISK_REGISTER.md

5.9 KiB
Raw Permalink Blame History

Payment Risk Register

Each row is one discrete payment feature or flow in nigig-pay. Risk = Likelihood × Impact. Updated after Phase 0 fixes.


1. USSD Dispatch

Attribute Value
Feature dispatch_ussd() — types into Safaricom USSD dialog
Current Gate #[cfg(feature = "demo")] — disabled in production builds
Residual Risk Low (production), High (demo/development)
Remaining Issues No idempotency key. No server-side confirmation.
Next Action Phase 1: provider integration with idempotency

2. Biometric Authentication

Attribute Value
Feature Fingerprint gate before USSD dispatch
Previous Risk P0 — fail-open on error dispatched without auth
Current Gate Fail-closed: error marks payment as Failed
Residual Risk Low
Remaining Issues cfg!(feature = "demo") wraps the biometric prompt itself; in non-demo builds, biometric is skipped entirely (but dispatch is also blocked).
Next Action Phase 1: biometric in all builds, dispatch gated by provider auth

3. PIN Handling

Attribute Value
Feature M-Pesa PIN stored in SharedPreferences for AccessibilityService
Previous Risk P0 — PIN persisted indefinitely across sessions
Current Gate Phase 0 removes the Rust KEY_PIN write and the Android AccessibilityService now removes any stale key then fails closed at the PIN step. No normal or demo flow can hand a PIN to SharedPreferences.
Residual Risk No payment PIN persistence path remains. The legacy AccessibilityService must still be removed or kept disabled until an authorised provider integration exists.
Next Action Phase 5: replace the legacy USSD bridge with an authorised provider integration; do not restore PIN handoff.

4. Auto-Retry

Attribute Value
Feature 5 retries with exponential backoff on retryable errors
Previous Risk High — no idempotency key, can duplicate payments
Current Gate Automatic replay was removed. A dispatch error is surfaced and requires explicit reconciliation/new user action.
Residual Risk No automatic retry path remains. Provider-side idempotency is still required before any future production gateway is enabled.
Next Action Phase 5: provider idempotency + reconciliation before enabling an authorised gateway.

5. Bulk Payments

Attribute Value
Feature Sequential batch USSD from CSV
Previous Risk Critical — no provider, no reconciliation, no audit
Current Gate Legacy bulk dispatch is disabled because the PIN handoff is disabled and no provider gateway exists.
Residual Risk No functioning batch payment path remains. A future provider batch feature requires idempotency, reconciliation, limits, and audit export.
Remaining Issues No authorised provider rail. No post-batch audit export.
Next Action Phase 5: only after provider integration + reconciliation model.

6. SMS Observation

Attribute Value
Feature Parse M-Pesa SMS from inbox to detect transaction outcomes
Previous Risk High — raw SMS persisted to disk, no sender validation
Current Gate raw_message no longer written to PSV. Renamed VerifiedObservedEvidence.
Residual Risk Medium — SMS remains untrusted evidence and sender labels can be spoofed.
Remaining Issues Sender provenance is not provider authentication. Evidence must remain non-settlement data.
Next Action Phase 5: provider confirmation; Phase 7: consent-safe adversarial SMS corpus.

7. Transaction Storage (PSV)

Attribute Value
Feature Flat pipe-delimited file for transaction records
Residual Risk Medium — legacy tracker still uses f64 money and remains a compatibility path.
Remaining Issues Domain/storage use exact money and integrity checks; tracker/UI consumers still need the Phase 6 money migration.
Next Action Phase 6: migrate tracker UI/parser consumers to exact minor-unit money.

8. R-SEC-001: Cloudflare API token committed to the repository

Attribute Value
Discovered 2026-07-27, during Phase 1 completion
Severity High
Description A live Cloudflare API token (cfut_Jviss2Pz…) was committed in plaintext in README.md.
Exposure Present since the Initial commit (cc05abd) and pushed to a public remote. It is readable in git history by anyone who has ever cloned or can clone the repository.
Immediate action taken Removed from README.md in the working tree; the example now reads the token from $CLOUDFLARE_API_TOKEN.
Required action (owner) Rotate the token in the Cloudflare dashboard. Redaction from the tip commit does not revoke it and does not remove it from history. Treat it as compromised.
Optional follow-up Purge from history with git filter-repo, accepting that this rewrites every published commit hash and requires all clones to re-clone. Rotation is mandatory; purging is not a substitute for it.
Preventive control Add secret scanning to CI. Never place a credential in a tracked file.

Summary: Post-Phase 0 Status

Severity Count Notes
Critical (production) 0 Tracker-only production path has no working PIN/USSD dispatch route.
Critical (legacy demo) 0 PIN handoff and automatic replay are disabled; legacy automation fails closed at the PIN step.
High 3 No provider confirmation, legacy tracker f64 money, Android key provisioning not implemented.
High (credential) 1 R-SEC-001 Cloudflare token in git history — rotation required.
Medium 2 SMS sender/provenance is untrusted; legacy tracker remains a compatibility path.
Low 1 Hard-coded fee table.