| name | pentest-mobile-react-native |
| description | Pentest de mobile React Native — OWASP MASVS L1/L2 + Mobile Top 10 (2024).
Cobre insecure storage, SSL pinning, root/jailbreak, deeplink hijack, WebView injection,
Hermes bytecode, OTA updates (Expo/CodePush), Frida hooks, anti-tamper e app signing.
TRIGGERS: pentest mobile, pentest react native, react native security, masvs, mobile top 10, ssl pinning, deeplink, jailbreak detection, hermes, expo updates, mobile storage, android manifest, ios plist
|
📱 pentest-mobile-react-native — Auditoria Ofensiva de React Native
Cobre RN bare workflow, Expo managed e Expo bare. Base normativa: OWASP MASVS (L1/L2) + Mobile Top 10 2024 + MASTG (testing guide).
Required Reading
app.json / app.config.ts (Expo)
android/app/src/main/AndroidManifest.xml
android/app/build.gradle
ios/*/Info.plist
metro.config.js
package.json e nativo (pods, gradle)
M1 — Improper Credential Usage
Hardcoded secrets no bundle
rg -n "(apiKey|secret|clientSecret|bearer|accessKey)\s*[:=]" apps/mobile/src/ -i
rg -n "BEGIN (RSA|OPENSSH|EC) PRIVATE KEY" apps/mobile/
RN Bundle distribui TODO o JS para o dispositivo. Qualquer constante no bundle está pública. Extração:
unzip -p app.apk assets/index.android.bundle > bundle.js
pnpm dlx hermes-assemble-strings main.jsbundle
pnpm dlx hbctool disasm main.hbc out/
M2 — Inadequate Supply Chain Security
pnpm audit --audit-level=high
pnpm dlx osv-scanner -r apps/mobile
M3 — Insecure Authentication/Authorization
rg -n "AsyncStorage\.(setItem|getItem)" apps/mobile/src/ | rg -i "token|jwt|password|secret"
rg -n "MMKV|react-native-keychain|SecureStore" apps/mobile/src/
Attack demo: em dispositivo root/emulador, AsyncStorage fica em /data/data/<pkg>/files/RKStorage — extrair com adb pull.
M4 — Insufficient Input/Output Validation
rg -n "WebView" apps/mobile/src/ -A 10 | rg -n "originWhitelist|injectedJavaScript|onMessage"
rg -n "eval\(|new Function\(" apps/mobile/src/
M5 — Insecure Communication
TLS + SSL Pinning
rg -n "NSAllowsArbitraryLoads|NSExceptionAllowsInsecureHTTPLoads" ios/
rg -n "usesCleartextTraffic|network_security_config" android/
rg -n "react-native-ssl-pinning|cert-pinner" apps/mobile/package.json
Attack demo: interceptar com mitmproxy e burp — se capturar tráfego cifrado legível, pinning falhou.
M6 — Inadequate Privacy Controls
rg -n "console\.(log|warn|info|debug)" apps/mobile/src/ | wc -l
rg -n "<uses-permission" android/app/src/main/AndroidManifest.xml
plutil -p ios/*/Info.plist | rg -i "UsageDescription"
M7 — Insufficient Binary Protections
Root/Jailbreak detection
Anti-debug / Anti-tamper
Frida/objection
Descrever no relatório como testar:
frida-ps -Uai
objection -g com.seuapp.mobile explore
M8 — Security Misconfiguration (antigo M10 reorganizado)
Deeplink Hijack
rg -n "scheme:" android/app/src/main/AndroidManifest.xml -A 5
cat app.json | jq '.expo.scheme, .expo.ios.associatedDomains, .expo.android.intentFilters'
Attack demo (Android):
adb shell am start -W -a android.intent.action.VIEW -d "myapp://transfer?to=attacker&amount=9999" com.seuapp
WebView
M9 — Insecure Data Storage
Locais a auditar em dispositivo root:
- Android:
/data/data/<pkg>/{databases,shared_prefs,files,cache}
- iOS:
~/Library/Containers/<bundle>/Data/{Documents,Library,tmp}
Bibliotecas:
- ❌
AsyncStorage → dados em claro
- ⚠️
react-native-mmkv → NÃO é criptografado por padrão; usar encryptionKey
- ✅
expo-secure-store → Keychain/Keystore
- ✅
react-native-keychain com ACCESSIBLE_WHEN_UNLOCKED_THIS_DEVICE_ONLY
- ✅
react-native-encrypted-storage (lib específica de storage cifrado)
rg -n "new MMKV\(" apps/mobile/src/ -A 3
rg -n "setGenericPassword|setInternetCredentials" apps/mobile/src/
M10 — Insufficient Cryptography
rg -n "md5|sha1|DES|createCipher\(" apps/mobile/src/ -i
OTA Updates (Expo EAS Update / CodePush)
Altíssimo impacto: atualização OTA é injeção remota de código.
cat app.json | jq '.expo.updates'
rg -n "updates\.checkForUpdateAsync|updates\.fetchUpdateAsync" apps/mobile/src/
App Signing & Distribuição
Android
iOS
rg -n "storeFile|storePassword|keyAlias" android/gradle.properties android/app/build.gradle
Output Snippet
### 📱 Mobile (React Native) — N findings
| ID | Sev | MASVS | CWE | File:Line | Issue |
|----|---|---|---|---|---|
| M-001 | 🔴 Critical | MSTG-STORAGE-1 | CWE-312 | apps/mobile/src/auth/storage.ts:14 | JWT em `AsyncStorage` (texto claro) |
| M-002 | 🟠 High | MSTG-NETWORK-4 | CWE-295 | android/.../network_security_config.xml | Sem SSL pinning |
| M-003 | 🟠 High | MSTG-PLATFORM-3 | CWE-939 | AndroidManifest.xml:22 | Deeplink sem `autoVerify` |
Anti-patterns a SEMPRE reportar
- JWT/PII em
AsyncStorage ou MMKV sem encryptionKey
- Ausência de SSL pinning em app financeiro/saúde
- WebView com
javaScriptEnabled + source={{uri}} de input externo
android:allowBackup="true" em app com dados sensíveis
- Deeplink executando ação financeira sem confirmação
- OTA update sem code signing
console.log de token/PII não removido em produção
jail-monkey instalado mas nunca chamado