# Sensitive permissions use proper permission API

- **Pattern:** `ab-001896` (`mobile-permissions-privacy.permission-requests.sensitive-permissions-api`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001896
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001896)

## 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`.

```typescript
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-use` or `always` explicitly (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-permissions` or for Expo, use `expo-permissions`:

  ```typescript
  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
- owasp A01
- external react-native-permissions — https://github.com/zoontek/react-native-permissions

Taxons: access-control

HTML version: https://auditbuffet.com/patterns/ab-001896
