cyberaudit-skill 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +77 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +241 -0
  4. package/dist/mcp-server.d.ts +2 -0
  5. package/dist/mcp-server.js +126 -0
  6. package/package.json +58 -0
  7. package/skills/cyberaudit/AGENT-BOOT.md +122 -0
  8. package/skills/cyberaudit/COMMANDS.md +1125 -0
  9. package/skills/cyberaudit/INSTALL.md +311 -0
  10. package/skills/cyberaudit/MASTER.md +194 -0
  11. package/skills/cyberaudit/README.md +154 -0
  12. package/skills/cyberaudit/USAGE-GUIDE.md +107 -0
  13. package/skills/cyberaudit/mobile/MOBILE-CHECKLIST.md +245 -0
  14. package/skills/cyberaudit/mobile/MOBILE-PHILOSOPHY.md +352 -0
  15. package/skills/cyberaudit/mobile/MOBILE-REMEDIATION-LIBRARY.md +468 -0
  16. package/skills/cyberaudit/mobile/MOBILE-THREAT-MODELS.md +279 -0
  17. package/skills/cyberaudit/mobile/frameworks/EXPO.md +247 -0
  18. package/skills/cyberaudit/mobile/frameworks/FLUTTER.md +338 -0
  19. package/skills/cyberaudit/mobile/frameworks/IONIC.md +248 -0
  20. package/skills/cyberaudit/mobile/frameworks/REACT-NATIVE.md +479 -0
  21. package/skills/cyberaudit/mobile/vulnerabilities/AUTH-MOBILE.md +160 -0
  22. package/skills/cyberaudit/mobile/vulnerabilities/BINARY-ANALYSIS.md +193 -0
  23. package/skills/cyberaudit/mobile/vulnerabilities/CRYPTO-MOBILE.md +192 -0
  24. package/skills/cyberaudit/mobile/vulnerabilities/IPC-DEEPLINKS.md +231 -0
  25. package/skills/cyberaudit/mobile/vulnerabilities/NETWORK-MOBILE.md +165 -0
  26. package/skills/cyberaudit/mobile/vulnerabilities/PERMISSIONS.md +180 -0
  27. package/skills/cyberaudit/mobile/vulnerabilities/RUNTIME-MOBILE.md +214 -0
  28. package/skills/cyberaudit/mobile/vulnerabilities/STORAGE.md +197 -0
  29. package/skills/cyberaudit/reports/EXECUTIVE-SUMMARY-TEMPLATE.md +188 -0
  30. package/skills/cyberaudit/reports/REPORT-TEMPLATE-MOBILE.md +410 -0
  31. package/skills/cyberaudit/reports/REPORT-TEMPLATE-WEB.md +222 -0
  32. package/skills/cyberaudit/shared/COMPLIANCE.md +307 -0
  33. package/skills/cyberaudit/shared/CVSS-GUIDE.md +175 -0
  34. package/skills/cyberaudit/shared/OWASP-MAPPER.md +130 -0
  35. package/skills/cyberaudit/shared/SEVERITY-SCORING.md +102 -0
  36. package/skills/cyberaudit/shared/THREAT-MODELING.md +112 -0
  37. package/skills/cyberaudit/web/WEB-CHECKLIST.md +222 -0
  38. package/skills/cyberaudit/web/WEB-PHILOSOPHY.md +308 -0
  39. package/skills/cyberaudit/web/WEB-REMEDIATION-LIBRARY.md +665 -0
  40. package/skills/cyberaudit/web/WEB-THREAT-MODELS.md +460 -0
  41. package/skills/cyberaudit/web/frameworks/ANGULAR.md +169 -0
  42. package/skills/cyberaudit/web/frameworks/EXPRESS.md +185 -0
  43. package/skills/cyberaudit/web/frameworks/LARAVEL.md +371 -0
  44. package/skills/cyberaudit/web/frameworks/NESTJS.md +337 -0
  45. package/skills/cyberaudit/web/frameworks/NEXTJS.md +352 -0
  46. package/skills/cyberaudit/web/frameworks/REACT.md +346 -0
  47. package/skills/cyberaudit/web/frameworks/VUE.md +205 -0
  48. package/skills/cyberaudit/web/vulnerabilities/AUTH-AUTHZ.md +117 -0
  49. package/skills/cyberaudit/web/vulnerabilities/BUSINESS-LOGIC.md +603 -0
  50. package/skills/cyberaudit/web/vulnerabilities/CORS.md +117 -0
  51. package/skills/cyberaudit/web/vulnerabilities/CSRF.md +131 -0
  52. package/skills/cyberaudit/web/vulnerabilities/DESERIALIZATION.md +96 -0
  53. package/skills/cyberaudit/web/vulnerabilities/HEADERS.md +105 -0
  54. package/skills/cyberaudit/web/vulnerabilities/IDOR-BOLA.md +153 -0
  55. package/skills/cyberaudit/web/vulnerabilities/INJECTION.md +165 -0
  56. package/skills/cyberaudit/web/vulnerabilities/SECRETS.md +119 -0
  57. package/skills/cyberaudit/web/vulnerabilities/SSRF.md +124 -0
  58. package/skills/cyberaudit/web/vulnerabilities/SUPPLY-CHAIN.md +142 -0
  59. package/skills/cyberaudit/web/vulnerabilities/XSS.md +133 -0
  60. package/skills/cyberaudit/web/vulnerabilities/XXE.md +94 -0
@@ -0,0 +1,479 @@
1
+ # ⚛️ REACT NATIVE — SECURITY AUDIT GUIDE
2
+ # Comprehensive audit guide for React Native applications
3
+
4
+ ═══════════════════════════════════════════════════════════════
5
+ REACT NATIVE — SECURITY ARCHITECTURE
6
+ ═══════════════════════════════════════════════════════════════
7
+
8
+ UNDERSTANDING THE ARCHITECTURE TO AUDIT CORRECTLY
9
+ ─────────────────────────────────────────────────────
10
+
11
+ [JavaScript Thread] ←→ [Bridge / JSI] ←→ [Native Thread]
12
+ ↑ ↑
13
+ React Native Code Native modules
14
+ Business logic System APIs
15
+ App state Storage, Camera...
16
+
17
+ SECURITY IMPLICATIONS:
18
+ → The JS bundle is packaged in the app = extractable
19
+ → The Bridge = attack surface between JS and native
20
+ → Expo managed = less control over native modules
21
+ → Bare workflow = more control, more responsibility
22
+
23
+ ═══════════════════════════════════════════════════════════════
24
+ VULNERABLE REACT NATIVE PATTERNS
25
+ ═══════════════════════════════════════════════════════════════
26
+
27
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
28
+ UNSECURE STORAGE
29
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
30
+
31
+ CRITICAL PATTERN 1 — AsyncStorage with sensitive data
32
+ DETECT:
33
+ AsyncStorage.setItem('token', accessToken)
34
+ AsyncStorage.setItem('user_data', JSON.stringify(user))
35
+ AsyncStorage.setItem('password', password)
36
+ AsyncStorage.setItem('credit_card', cardNumber)
37
+ AsyncStorage.setItem('session', sessionId)
38
+
39
+ // Also via wrappers:
40
+ storage.set('auth', token) // if storage = AsyncStorage
41
+ cache.store('user', data) // check implementation
42
+
43
+ UNDERSTAND:
44
+ AsyncStorage = unencrypted files on the system
45
+ Android: /data/data/com.yourapp/databases/
46
+ iOS: NSLibraryDirectory unencrypted
47
+ Readable with root/jailbreak OR unencrypted backup
48
+
49
+ FIX:
50
+ // Installation
51
+ // yarn add react-native-keychain
52
+
53
+ import * as Keychain from 'react-native-keychain'
54
+
55
+ // Store the auth token
56
+ await Keychain.setGenericPassword(
57
+ 'auth-token',
58
+ accessToken,
59
+ {
60
+ service: 'com.yourapp.auth',
61
+ accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE,
62
+ accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
63
+ // WHEN_UNLOCKED_THIS_DEVICE_ONLY = not in iCloud backups
64
+ }
65
+ )
66
+
67
+ // Retrieve the token
68
+ const credentials = await Keychain.getGenericPassword({
69
+ service: 'com.yourapp.auth'
70
+ })
71
+ const token = credentials ? credentials.password : null
72
+
73
+ // For less sensitive data (preferences, config)
74
+ // react-native-encrypted-storage is acceptable
75
+ import EncryptedStorage from 'react-native-encrypted-storage'
76
+
77
+ await EncryptedStorage.setItem(
78
+ 'user_preferences',
79
+ JSON.stringify(preferences)
80
+ )
81
+
82
+ HIGH PATTERN 2 — MMKV / Redux Persist without encryption
83
+ DETECT:
84
+ import { MMKV } from 'react-native-mmkv'
85
+ const storage = new MMKV() // No encryption!
86
+ storage.set('user.token', token)
87
+
88
+ // Redux Persist with AsyncStorage
89
+ const persistConfig = {
90
+ key: 'root',
91
+ storage: AsyncStorage, // Unencrypted!
92
+ // Whitelist without filtering sensitive data
93
+ whitelist: ['auth', 'user', 'payment']
94
+ }
95
+
96
+ FIX:
97
+ // MMKV with encryption
98
+ import { MMKV } from 'react-native-mmkv'
99
+
100
+ // Encryption key must come from Keychain!
101
+ const encryptionKey = await getEncryptionKeyFromKeychain()
102
+
103
+ const storage = new MMKV({
104
+ id: 'secure-storage',
105
+ encryptionKey: encryptionKey
106
+ })
107
+
108
+ // Redux Persist: do NOT persist sensitive data
109
+ const persistConfig = {
110
+ key: 'root',
111
+ storage: MMKVStorage, // with encryption
112
+ // Blacklist sensitive data
113
+ blacklist: ['auth', 'payment'],
114
+ // OR whitelist only what is safe
115
+ whitelist: ['ui', 'settings', 'theme']
116
+ }
117
+
118
+ // Auth tokens → Keychain only
119
+
120
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
121
+ UNSECURE WEBVIEW
122
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
123
+
124
+ CRITICAL PATTERN 3 — WebView with exposed JS bridge
125
+ DETECT:
126
+ <WebView
127
+ source={{ uri: userUrl }} // User-controlled URL!
128
+ javaScriptEnabled={true}
129
+ onMessage={handleMessage} // Exposed bridge
130
+ />
131
+
132
+ // Even worse:
133
+ <WebView
134
+ source={{ uri: `https://yourapp.com?data=${userInput}` }}
135
+ injectedJavaScript={userScript} // CRITICAL
136
+ />
137
+
138
+ FIX:
139
+ <WebView
140
+ // Controlled source
141
+ source={{ uri: 'https://trusted.yourapp.com/content' }}
142
+
143
+ // If dynamic URL, strict whitelist
144
+ onShouldStartLoadWithRequest={(request) => {
145
+ const allowedHosts = ['yourapp.com', 'trusted-partner.com']
146
+ const host = new URL(request.url).hostname
147
+ return allowedHosts.includes(host)
148
+ }}
149
+
150
+ // Messages validated on React Native side
151
+ onMessage={(event) => {
152
+ const data = JSON.parse(event.nativeEvent.data)
153
+
154
+ // Validate message type
155
+ const allowedTypes = ['navigation', 'shareContent', 'payment_result']
156
+ if (!allowedTypes.includes(data.type)) return
157
+
158
+ // Validate data by type
159
+ handleValidatedMessage(data)
160
+ }}
161
+
162
+ // Disable JS if not needed
163
+ javaScriptEnabled={false} // If possible
164
+
165
+ // Disable local file access
166
+ allowFileAccess={false}
167
+ allowFileAccessFromFileURLs={false}
168
+ allowUniversalAccessFromFileURLs={false}
169
+ />
170
+
171
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
172
+ LOGS IN PRODUCTION
173
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
174
+
175
+ MEDIUM PATTERN 4 — console.log with sensitive data
176
+ DETECT:
177
+ console.log('User logged in:', user)
178
+ console.log('Token:', token)
179
+ console.log('API Response:', response.data)
180
+ console.log('Payment data:', paymentInfo)
181
+ console.warn('Auth error:', authError) // contains details?
182
+
183
+ // Often forgotten patterns:
184
+ console.log(JSON.stringify(reduxState)) // Full state!
185
+ console.log('Request:', config) // Headers with auth token!
186
+
187
+ FIX:
188
+ // utils/logger.ts
189
+ const isDev = __DEV__
190
+
191
+ export const logger = {
192
+ // Log only in development
193
+ debug: (...args: any[]) => {
194
+ if (isDev) console.log('[DEBUG]', ...args)
195
+ },
196
+
197
+ info: (...args: any[]) => {
198
+ if (isDev) console.info('[INFO]', ...args)
199
+ },
200
+
201
+ warn: (...args: any[]) => {
202
+ if (isDev) console.warn('[WARN]', ...args)
203
+ },
204
+
205
+ // Errors can go to crash reporting service
206
+ // but WITHOUT sensitive data
207
+ error: (message: string, error?: Error) => {
208
+ if (isDev) console.error('[ERROR]', message, error)
209
+
210
+ // In production: send only message, not data
211
+ crashReporter.log(message, {
212
+ errorType: error?.name,
213
+ // No full stack trace with user data
214
+ })
215
+ },
216
+
217
+ // Never log this data, even in dev
218
+ sensitive: () => {
219
+ // Intentional no-op
220
+ }
221
+ }
222
+
223
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
224
+ REACT NATIVE DEEP LINKS
225
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
226
+
227
+ HIGH PATTERN 5 — Deep links without validation
228
+ DETECT:
229
+ // Basic handling without validation
230
+ Linking.addEventListener('url', ({ url }) => {
231
+ const route = url.replace('myapp://', '')
232
+ navigation.navigate(route) // ROUTE INJECTION
233
+ })
234
+
235
+ // React Navigation without validation
236
+ const config = {
237
+ screens: {
238
+ Payment: 'payment/:amount', // amount not validated!
239
+ Profile: 'user/:userId', // IDOR possible!
240
+ }
241
+ }
242
+
243
+ FIX:
244
+ import { Linking } from 'react-native'
245
+
246
+ // Complete deep link validation
247
+ const handleDeepLink = async (url: string) => {
248
+ // 1. Parse URL
249
+ let parsed: URL
250
+ try {
251
+ parsed = new URL(url)
252
+ } catch {
253
+ return // Invalid URL
254
+ }
255
+
256
+ // 2. Verify allowed scheme
257
+ const allowedSchemes = ['myapp:', 'https:']
258
+ if (!allowedSchemes.includes(parsed.protocol)) return
259
+
260
+ // 3. If HTTPS, verify host
261
+ if (parsed.protocol === 'https:') {
262
+ const allowedHosts = ['yourapp.com', 'app.yourapp.com']
263
+ if (!allowedHosts.includes(parsed.hostname)) return
264
+ }
265
+
266
+ // 4. Route to allowed screens
267
+ const path = parsed.pathname.split('/').filter(Boolean)
268
+
269
+ switch (path[0]) {
270
+ case 'product': {
271
+ const productId = parseInt(path[1], 10)
272
+ if (isNaN(productId) || productId <= 0) return
273
+ navigation.navigate('Product', { id: productId })
274
+ break
275
+ }
276
+
277
+ case 'payment': {
278
+ // Sensitive routes require auth
279
+ const session = await getCurrentSession()
280
+ if (!session) {
281
+ navigation.navigate('Login', { returnTo: url })
282
+ return
283
+ }
284
+ // Parameters validated server-side, not client-side
285
+ navigation.navigate('Payment')
286
+ break
287
+ }
288
+
289
+ case 'reset-password': {
290
+ const token = parsed.searchParams.get('token')
291
+ // Opaque token, validated by server
292
+ if (!token || token.length < 32) return
293
+ navigation.navigate('ResetPassword', { token })
294
+ break
295
+ }
296
+
297
+ default:
298
+ // Unknown route → ignore
299
+ return
300
+ }
301
+ }
302
+
303
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
304
+ REACT NATIVE CERTIFICATE PINNING
305
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
306
+
307
+ HIGH PATTERN 6 — No certificate pinning
308
+ DETECT:
309
+ // Standard fetch without pinning
310
+ fetch('https://api.yourapp.com/users')
311
+
312
+ // Axios without pinning
313
+ axios.get('https://api.yourapp.com/data')
314
+
315
+ // None of the following libraries imported:
316
+ // react-native-ssl-pinning
317
+ // react-native-pinch
318
+ // No native pinning module
319
+
320
+ FIX:
321
+ // Installation
322
+ // yarn add react-native-ssl-pinning
323
+
324
+ import { fetch as sslFetch } from 'react-native-ssl-pinning'
325
+
326
+ // Get certificate hash:
327
+ // openssl s_client -connect api.yourapp.com:443 | \
328
+ // openssl x509 -pubkey -noout | \
329
+ // openssl pkey -pubin -outform der | \
330
+ // openssl dgst -sha256 -binary | base64
331
+
332
+ const API_PINS = [
333
+ 'YOUR_PRIMARY_PIN_BASE64==',
334
+ 'YOUR_BACKUP_PIN_BASE64==', // Always have a backup!
335
+ ]
336
+
337
+ export const secureApi = {
338
+ get: async (endpoint: string, options = {}) => {
339
+ return sslFetch(`https://api.yourapp.com${endpoint}`, {
340
+ method: 'GET',
341
+ sslPinning: {
342
+ certs: API_PINS,
343
+ },
344
+ headers: {
345
+ 'Authorization': `Bearer ${await getToken()}`,
346
+ 'Content-Type': 'application/json',
347
+ },
348
+ ...options,
349
+ })
350
+ },
351
+
352
+ post: async (endpoint: string, body: object) => {
353
+ return sslFetch(`https://api.yourapp.com${endpoint}`, {
354
+ method: 'POST',
355
+ sslPinning: {
356
+ certs: API_PINS,
357
+ },
358
+ body: JSON.stringify(body),
359
+ headers: {
360
+ 'Authorization': `Bearer ${await getToken()}`,
361
+ 'Content-Type': 'application/json',
362
+ },
363
+ })
364
+ }
365
+ }
366
+
367
+ // IMPORTANT: Pin rotation plan
368
+ // 1. Generate new pins 30 days before expiration
369
+ // 2. Deploy app with [old pin, new pin]
370
+ // 3. Wait >95% of users have migrated
371
+ // 4. Deploy app with [new pin] only
372
+
373
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
374
+ BACKGROUND SCREENSHOT (iOS/Android)
375
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
376
+
377
+ MEDIUM PATTERN 7 — Sensitive data visible in switcher
378
+ DETECT:
379
+ // No background screenshot protection
380
+ // No AppState listener to hide data
381
+ // No FLAG_SECURE (Android) or blurring (iOS)
382
+
383
+ FIX:
384
+ import { AppState, Platform } from 'react-native'
385
+ import { useEffect, useState } from 'react'
386
+
387
+ // Background protection hook
388
+ export const useBackgroundProtection = () => {
389
+ const [isBackground, setIsBackground] = useState(false)
390
+
391
+ useEffect(() => {
392
+ const subscription = AppState.addEventListener(
393
+ 'change',
394
+ (nextAppState) => {
395
+ setIsBackground(nextAppState === 'background' ||
396
+ nextAppState === 'inactive')
397
+ }
398
+ )
399
+
400
+ return () => subscription.remove()
401
+ }, [])
402
+
403
+ return isBackground
404
+ }
405
+
406
+ // Protection component
407
+ export const ProtectedScreen = ({ children }) => {
408
+ const isBackground = useBackgroundProtection()
409
+
410
+ if (isBackground) {
411
+ return (
412
+ <View style={styles.blurScreen}>
413
+ <Image source={require('./assets/logo.png')} />
414
+ // Masks content with app logo
415
+ </View>
416
+ )
417
+ }
418
+
419
+ return children
420
+ }
421
+
422
+ // Android: FLAG_SECURE (prevents screenshots)
423
+ // In MainActivity.java:
424
+ // getWindow().setFlags(
425
+ // WindowManager.LayoutParams.FLAG_SECURE,
426
+ // WindowManager.LayoutParams.FLAG_SECURE
427
+ // );
428
+
429
+ // Library: react-native-screenshot-prevent
430
+
431
+ ═══════════════════════════════════════════════════════════════
432
+ COMPLETE REACT NATIVE CHECKLIST
433
+ ═══════════════════════════════════════════════════════════════
434
+
435
+ STORAGE
436
+ □ AsyncStorage without sensitive data ?
437
+ □ Keychain for tokens and passwords ?
438
+ □ MMKV with encryption if used ?
439
+ □ Redux Persist: sensitive data blacklisted ?
440
+ □ SQLite encrypted (SQLCipher) if local database ?
441
+
442
+ NETWORK
443
+ □ Certificate pinning implemented ?
444
+ □ Backup pins present ?
445
+ □ All endpoints in HTTPS ?
446
+ □ Tokens in headers, not query params ?
447
+ □ Network Security Config (Android) configured ?
448
+
449
+ WEBVIEW
450
+ □ URLs strictly whitelisted ?
451
+ □ javaScriptEnabled justified ?
452
+ □ WebView messages validated ?
453
+ □ allowFileAccess=false ?
454
+ □ JavaScript Bridge minimal and secure ?
455
+
456
+ CODE
457
+ □ console.log disabled in production ?
458
+ □ __DEV__ used for debug logs ?
459
+ □ No API keys in JS code ?
460
+ □ Source maps disabled in production ?
461
+ □ Hermes enabled (Android) ?
462
+
463
+ DEEP LINKS
464
+ □ All parameters validated ?
465
+ □ Allowed routes whitelisted ?
466
+ □ Auth checked before sensitive actions ?
467
+ □ Minimal intent filters (Android) ?
468
+
469
+ INTERFACE
470
+ □ Screenshot protection in background ?
471
+ □ Sensitive fields with secureTextEntry ?
472
+ □ Clipboard protection on sensitive data ?
473
+ □ Autocomplete disabled on sensitive fields ?
474
+
475
+ BUILD
476
+ □ ProGuard/R8 enabled in Android release ?
477
+ □ Debug builds separate from release builds ?
478
+ □ Signing config secured ?
479
+ □ Dependencies audited ?
@@ -0,0 +1,160 @@
1
+ # 🔑 AUTH MOBILE — VULNERABILITY GUIDE
2
+ # Authentication and session management on mobile
3
+
4
+ ═══════════════════════════════════════════════════════════════
5
+ MOBILE AUTH VS WEB AUTH
6
+ ═══════════════════════════════════════════════════════════════
7
+
8
+ WHAT IS DIFFERENT ON MOBILE
9
+ ─────────────────────────────────
10
+ WEB MOBILE
11
+ ────────────────────── ──────────────────────────────
12
+ HttpOnly Cookies Tokens in Keychain/Keystore
13
+ Server sessions Stateless JWT often used
14
+ Browser cache cleared Data persists on device
15
+ No physical access Device can be stolen
16
+ Logout = cookie cleared Logout = token actively deleted
17
+ MFA via web MFA via biometrics or TOTP app
18
+
19
+ MOBILE-SPECIFIC RISKS
20
+ ───────────────────────────────
21
+ 1. Stolen token = permanent access if no expiration
22
+ 2. Stolen device = access if token in cleartext
23
+ 3. Biometrics bypassable if poorly implemented
24
+ 4. Session persists indefinitely on device
25
+ 5. Tokens copyable between devices if not device-bound
26
+
27
+ ═══════════════════════════════════════════════════════════════
28
+ MOBILE AUTH VULNERABILITIES
29
+ ═══════════════════════════════════════════════════════════════
30
+
31
+ VULN-AUTH-001 — Token Stored Insecurely
32
+ Severity: HIGH (CVSS 7.5)
33
+ MASVS : MASVS-AUTH-2
34
+
35
+ The auth token = the keys to the kingdom.
36
+ Its storage must be handled with the same rigor
37
+ as a password.
38
+
39
+ See VULN-STORAGE-001 for the complete fix.
40
+
41
+ VULN-AUTH-002 — Biometrics Implemented as Simple Boolean
42
+ Severity: HIGH (CVSS 7.1)
43
+ MASVS : MASVS-AUTH-3
44
+
45
+ Explanation:
46
+ The vulnerable implementation:
47
+ 1. User places finger
48
+ 2. Biometric SDK returns true/false
49
+ 3. If true → display sensitive data
50
+
51
+ With Frida, hook the method and always return true.
52
+ Even without Frida, if the app checks a simple
53
+ "biometric_ok=true" flag server-side, it's trivially bypassable.
54
+
55
+ The correct implementation:
56
+ Biometrics must unlock a CRYPTOGRAPHIC KEY
57
+ that is needed to decrypt data or
58
+ sign a server request.
59
+ Without the key → no access, even if the check is bypassed.
60
+
61
+ Fix:
62
+ // react-native-keychain — Biometrics linked to key
63
+ // See REM-MOB-007 in MOBILE-REMEDIATION-LIBRARY.md
64
+
65
+ VULN-AUTH-003 — No Inactivity Timeout
66
+ Severity: MEDIUM (CVSS 5.5)
67
+ MASVS : MASVS-AUTH-2
68
+
69
+ Explanation:
70
+ If a user leaves their phone unlocked
71
+ with the app open, anyone can access it.
72
+
73
+ Banking, health, and finance apps MUST
74
+ implement an inactivity timeout.
75
+
76
+ Fix:
77
+ // React Native — Inactivity timeout
78
+ import { AppState } from 'react-native'
79
+
80
+ const INACTIVITY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
81
+
82
+ export const useInactivityTimeout = (
83
+ onTimeout: () => void
84
+ ) => {
85
+ const lastActivityRef = useRef(Date.now())
86
+ const timerRef = useRef<ReturnType<typeof setTimeout>>()
87
+
88
+ const resetTimer = useCallback(() => {
89
+ lastActivityRef.current = Date.now()
90
+ clearTimeout(timerRef.current)
91
+ timerRef.current = setTimeout(onTimeout, INACTIVITY_TIMEOUT)
92
+ }, [onTimeout])
93
+
94
+ useEffect(() => {
95
+ // Start timer
96
+ resetTimer()
97
+
98
+ // Listen for return to foreground
99
+ const sub = AppState.addEventListener('change', state => {
100
+ if (state === 'active') {
101
+ const elapsed = Date.now() - lastActivityRef.current
102
+ if (elapsed > INACTIVITY_TIMEOUT) {
103
+ onTimeout()
104
+ } else {
105
+ resetTimer()
106
+ }
107
+ }
108
+ })
109
+
110
+ return () => {
111
+ sub.remove()
112
+ clearTimeout(timerRef.current)
113
+ }
114
+ }, [])
115
+
116
+ return resetTimer // Call on every user interaction
117
+ }
118
+
119
+ VULN-AUTH-004 — Non-Revocable Refresh Token
120
+ Severity: HIGH (CVSS 7.2)
121
+ MASVS : MASVS-AUTH-2
122
+
123
+ Explanation:
124
+ If a refresh token is stolen and cannot be revoked:
125
+ → Attacker has access as long as token is valid
126
+ → Even after password change
127
+ → Even after reporting the theft
128
+
129
+ Server-side fix (backend):
130
+ → Store refresh tokens in database
131
+ → Allow revocation (logout = DB invalidation)
132
+ → Implement rotation (each use generates a new token)
133
+ → Detect reuse (if old token reused → compromise)
134
+
135
+ // Rotation strategy:
136
+ // 1. Client sends refresh_token
137
+ // 2. Server checks validity in DB
138
+ // 3. Server generates new access_token AND new refresh_token
139
+ // 4. Server invalidates old refresh_token in DB
140
+ // 5. If old token is reused → invalidate ENTIRE family
141
+ // (sign of compromise)
142
+
143
+ VULN-AUTH-005 — Client Certificate (mTLS) Absent for Critical Apps
144
+ Severity: MEDIUM (CVSS 5.5)
145
+ MASVS : MASVS-AUTH-1
146
+
147
+ Context: Banking, health, government apps
148
+
149
+ Explanation:
150
+ Certificate pinning verifies the server.
151
+ mTLS (mutual TLS) ALSO allows the server
152
+ to verify that the request comes from YOUR app
153
+ on a LEGITIMATE DEVICE.
154
+
155
+ Without mTLS, any script can call your API
156
+ with a valid stolen token.
157
+ With mTLS, the device must present a client certificate.
158
+
159
+ Note: Complex implementation, reserved for critical apps.
160
+ Evaluate the security/complexity trade-off per context.