Sensitive permissions use proper permission API
Why it matters
Accessing device hardware through undocumented native paths instead of the platform's official permission API means the app bypasses the OS-level permission gate entirely. OWASP Mobile Top 10 A01 (Improper Credential Usage) includes improper access to device hardware as a credential misuse vector. CWE-272 (Least Privilege Violation) is directly triggered when an app reads from a sensor without first verifying it has been granted access. Beyond correctness, bypassing react-native-permissions or expo-permissions means your code will behave unpredictably when users revoke permissions mid-session, because the native module has no revocation-aware wrapper — the call will silently fail or crash instead of returning a denied status.
Severity rationale
High because bypassing the standard permission API means the app can silently access hardware after a user revokes permission mid-session, with no graceful fallback — a direct OWASP A01 and CWE-272 violation.
Remediation
Replace direct native module calls with react-native-permissions (bare React Native) or expo-permissions / expo-location (Expo). Always distinguish between LOCATION_WHEN_IN_USE and LOCATION_ALWAYS.
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions'
import { Platform } from 'react-native'
async function requestLocationPermission(): Promise<boolean> {
const permission =
Platform.OS === 'ios'
? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION
const result = await request(permission)
return result === RESULTS.GRANTED
}
For Expo, use the typed exports from expo-location, expo-camera, or expo-contacts — they wrap the same Keychain/Keystore-aware permission APIs and handle revocation correctly.
Detection
-
ID:
sensitive-permissions-api -
Severity:
high -
What to look for: List all sensitive permissions used (camera, location, contacts, calendar, photos, microphone, health). For each, check whether it is requested via a standard permission API (
react-native-permissions,expo-permissions) rather than direct native calls. Quote the actual import and API call used. -
Pass criteria: At least 100% of sensitive permissions are requested via a standard permission library or Expo API. Location permission requests specify
when-in-useoralwaysexplicitly (not just a generic location request). Report the count even on pass: "All N sensitive permissions use proper API." -
Fail criteria: Any sensitive permission is accessed directly without checking permission status first (e.g., calling native camera without a permission check). OR location permission does not distinguish between permission types.
-
Skip (N/A) when: App uses no sensitive permissions (no camera, location, contacts, calendar, photos, microphone, or health APIs).
-
Detail on fail: Specify which permissions bypass the API. Quote the actual code. Example:
"Camera is accessed directly via NativeModules.CameraModule without permission check"or"Location permission requested but 'always' vs 'when-in-use' distinction not implemented" -
Remediation: Use a standardized permission API to handle permission checks and requests. For React Native, use
react-native-permissionsor for Expo, useexpo-permissions:import { request, PERMISSIONS, RESULTS } from 'react-native-permissions' async function requestLocationPermission() { const result = await request( Platform.OS === 'ios' ? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE : PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION ) return result === RESULTS.GRANTED }
External references
- cwe · CWE-272 — Least Privilege Violation
- owasp:2021 · A01 — Broken Access Control
- external · react-native-permissions — react-native-permissions: Cross-platform permissions API
Taxons
History
- 2026-04-18·v1.0.0·Initial import from mobile-permissions-privacy·automated