Metadata-Version: 2.4
Name: fraudshield-mobile
Version: 1.0.0
Summary: Security and fraud-risk scanner for Flutter, Android, iOS and KMP fintech apps: scans source code and built .apk / .aab / .ipa files
Keywords: security,fraud,mobile,flutter,android,ios,kmp,fintech,masvs,apk,ipa
Classifier: Programming Language :: Python :: 3
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# FraudShield

A security and fraud-risk scanner for our mobile apps. Point it at **source code** (Flutter, Kotlin, SwiftUI, KMP) or a **built app** (`.apk`, `.aab`, `.ipa`). It reports weaknesses that attackers and scammers abuse, explains how each one gets abused, and tells you how to fix it.

- Pure Python 3.8+, no dependencies, no internet (except the optional `--deps` check). Your code never leaves your computer.
- Results are printed in the terminal and saved to an HTML report you can share. JSON and SARIF output are available for CI.
- Every finding is mapped to the **OWASP MASVS** mobile security standard.

## Install

```bash
brew install pipx && pipx ensurepath     # once, if you don't have pipx
pipx install fraudshield-mobile
```

Update later with `pipx upgrade fraudshield-mobile`.

## Quick start

```bash
# Source code: one app, or a folder full of apps
fraudshield ~/code/wallet-app
cd ~/code/wallet-app && fraudshield .

# Built apps: scan what you are about to ship
fraudshield build/app/outputs/flutter-apk/app-release.apk
fraudshield build/ios/ipa/Wallet.ipa

# Everything at once, plus a dependency check
fraudshield ~/code/wallet-app app-release.apk Wallet.ipa --deps
```

Open `fraudshield-report.html` to see the full report. You can filter it by severity and search it. It also includes a checklist of server-side fraud controls to confirm with the backend team.

## Why scan both source and the build?

| Source scan finds | Build scan finds |
|---|---|
| Insecure code: trust-all TLS, OTP/PIN checked in the app, tokens in SharedPreferences/UserDefaults, logging of PINs, weak crypto, WebView holes, bypass/test codes | What actually ships: keys injected by CI or `--dart-define`, `.env` files bundled into Flutter assets, debug builds, the **debug signing key**, development provisioning profiles, missing obfuscation |
| Config: AndroidManifest, network security config, Info.plist, Gradle, CI build commands | The compiled manifest and Info.plist, DEX strings, Flutter `libapp.so`, the iOS binary, bundled JSON/env files |

Run the source scan on every pull request. Run the build scan on the release artifact before uploading it to the Play Store or App Store.

## What it checks

| Area | Examples |
|---|---|
| **Secrets** | AWS keys, private keys, Paystack/Stripe `sk_live_`, Flutterwave secret keys, **MTN MoMo / Hubtel / M-Pesa credentials**, FCM server keys, JWTs, Google API keys, signing passwords, `.env` and `key.properties` contents |
| **Network** | Trust-all TrustManager or HostnameVerifier, `badCertificateCallback => true`, iOS trust-all challenge handlers, cleartext HTTP, ATS disabled, user CAs trusted, verbose HTTP logging (OkHttp, Ktor, Dio), staging URLs in release builds |
| **Storage** | Tokens or PINs in SharedPreferences, DataStore, UserDefaults, `@AppStorage`, multiplatform-settings, shared_preferences, GetStorage or Hive; weak Keychain protection; secrets copied to the clipboard; world-readable files |
| **Fraud logic** | OTP/PIN compared on the device, master/test OTPs and `bypassOtp` switches, KYC level or limits read from local storage, fees or totals computed in the app, WebViews opening URLs taken from deep links, custom-scheme deep links, intent redirection |
| **Auth** | Biometric login that is only a yes/no (Frida-bypassable), PIN typed into a visible `TextField` |
| **Crypto** | ECB/DES, MD5/SHA-1, hard-coded keys and IVs, predictable random OTPs |
| **Platform** | Debuggable builds, allowBackup, exported components, risky permissions (READ_SMS, SYSTEM_ALERT_WINDOW…), `UIFileSharingEnabled`, old TLS |
| **Missing defences** | Screenshot/screen-recording protection, root/jailbreak detection, certificate pinning, Play Integrity / App Attest / App Check, overlay (tap-jacking) protection, R8 or `--obfuscate` |
| **Dependencies** (`--deps`) | Known vulnerabilities from OSV.dev in `pubspec.lock`, Gradle / `libs.versions.toml` and `Package.resolved` |

## Options

| Option | What it does |
|---|---|
| `--fail-on high` | Exits with code 1 if any finding is `high` or worse. Use it in CI to block a release. |
| `--min-severity medium` | Hides findings below `medium`. |
| `--json out.json` / `--sarif out.sarif` | Machine-readable output. SARIF shows up in GitHub code scanning. |
| `--html path.html` / `--no-html` | Changes where the report is saved, or turns the report off. |
| `--deps` | Checks dependencies against OSV.dev. This sends package names and versions, nothing else. |
| `--exclude "legacy/*"` | Skips paths. The option can be repeated. |
| `--include-tests` | Also reports issues in test code. Secrets in tests are always reported. |
| `--write-baseline fs-baseline.json` / `--baseline fs-baseline.json` | Accepts today's findings, then reports only **new** ones. Useful when adopting the tool on an older app. |

### Silencing a false positive

Add a comment on the line, or on the line above it. Always say why:

```kotlin
Log.d(TAG, "token refreshed")  // fraudshield:ignore LOG001 - no value logged
```

Debug-only code is skipped automatically: `if (BuildConfig.DEBUG) { … }`, `if (kDebugMode) { … }` and `#if DEBUG … #endif`.

## Using it in CI

GitHub Actions:

```yaml
- run: pipx install fraudshield-mobile
- name: FraudShield (source)
  run: fraudshield . --fail-on high --sarif fraudshield.sarif --html fraudshield.html
- name: FraudShield (release build)
  run: fraudshield build/app/outputs/flutter-apk/app-release.apk build/ios/ipa/*.ipa --fail-on high --no-html
- uses: github/codeql-action/upload-sarif@v3
  if: always()
  with: { sarif_file: fraudshield.sarif }
- uses: actions/upload-artifact@v4
  if: always()
  with: { name: fraudshield-report, path: fraudshield.html }
```

Codemagic or a shell script: `pipx install fraudshield-mobile && fraudshield . --fail-on high || exit 1`

## Reading the grade

| Grade | Meaning |
|---|---|
| **F** | At least one critical finding: attackers can exploit it now. Don't release. |
| **D** | Three or more high findings. |
| **C** | At least one high finding. Fix before release. |
| **B** | Only medium or lower: hardening needed. Most apps without anti-tamper protection land here. |
| **A** | No significant issues found. |

## Limits (please read)

- The scanner matches **patterns**. It catches the common mistakes quickly, but it's not a penetration test. Some findings will need a human to confirm them, and some problems can't be seen by pattern matching.
- **It can't see your backend**, and most real fraud losses come from missing server-side controls: amount and fee recomputation, idempotency, OTP limits, IDOR checks, SIM-swap checks, velocity rules. The HTML report ends with a checklist for these.
- For **built apps**:
  - Native `FLAG_SECURE` is a numeric constant, so it can't be seen in a build. Confirm it with a source scan.
  - App Store-downloaded IPAs are encrypted. Scan the IPA exported from Xcode or CI instead.
  - For `.aab` files the manifest isn't decoded. Use `bundletool build-apks --mode=universal` and scan the APK too.
- Secret values are **masked** in all reports, so reports are safe to share.

## Code layout

| File | What's in it |
|---|---|
| `fraudshield/cli.py` | Command line: arguments, filtering, baseline, exit codes |
| `fraudshield/rules.py` | Every detection rule, with its severity, explanation, fix and MASVS mapping, plus the defence markers. **Most changes happen here.** |
| `fraudshield/scanner.py` | Rule engine, source-folder scanning, AndroidManifest / network-security-config / Info.plist / Gradle / CI checks, missing-defence checks, OSV dependency check |
| `fraudshield/binary_scanner.py` | `.apk` / `.aab` / `.ipa` decoding: Android binary XML, DEX strings, Mach-O, signing certificate and provisioning profile, bundled assets |
| `fraudshield/report.py` | Risk grade, terminal output, SARIF, HTML report, backend checklist |

## Development

```bash
python3 -m unittest discover -s tests -v      # 18 tests
python3 tests/make_test_apps.py               # builds vulnerable test APK/IPA into tests/build/
python3 fraudshield.py path/to/app            # run from this folder without installing
```

`tests/fixtures/` contains small, deliberately vulnerable Flutter, Kotlin, SwiftUI and KMP apps, plus one clean app that must produce **zero** findings. The fake keys are inserted at test time, so the repo never contains anything that looks like a real secret and GitHub push protection won't block it. Binary tests build real APKs and an IPA with the Android SDK and Xcode, and are skipped on machines without them.

To add a rule, add an `R(...)` entry to `RULES` in `fraudshield/rules.py`, add a vulnerable line to a fixture, and assert it in `tests/test_fraudshield.py`. Keep the clean app clean.
