# Permissions are justified and minimized

- **Pattern:** `ab-001944` (`mobile-store-readiness.build-config.permissions-justified`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001944
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001944)

## Why it matters

App stores actively audit permission declarations for proportionality — a notes app requesting `ACCESS_FINE_LOCATION` or `NSCameraUsageDescription` without a plausible justification triggers manual review and frequently results in rejection or removal. Under GDPR Art. 5(1)(c) (data minimisation) and CWE-272 (least privilege violation), requesting permissions beyond what your app's core function requires constitutes a legal compliance failure, not just a policy violation. Apple's privacy nutrition label (apple-privacy-permission-usage) surfaces every declared permission to users before install; overly broad permission sets reduce install conversion and increase uninstalls. iOS rejects binaries that declare a permission in `Info.plist` without a corresponding `NS*UsageDescription` string — this is an automated binary validation failure.

## Severity rationale

Medium because missing `NS*UsageDescription` strings trigger automated iOS binary rejection, and overly broad permission sets expose the app to GDPR Art. 5(1)(c) violations and store reviewer scrutiny.

## Remediation

Audit `app.json` for every declared permission and add a precise usage description for iOS. Remove any permissions your app does not actually invoke at runtime.

```json
// app.json
{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSCameraUsageDescription": "Used to scan QR codes for event check-in.",
        "NSPhotoLibraryUsageDescription": "Used to attach photos to your reports."
      }
    },
    "android": {
      "permissions": [
        "android.permission.CAMERA"
      ]
    }
  }
}
```

For each permission, verify with a code search that it is actually called (`Camera.requestCameraPermissionsAsync()`, etc.) — remove any that aren't. Cross-reference with the App Store Privacy & Data audit (`app-store-privacy-data`) for the full ATT and data collection declaration requirements.

## Detection

- **ID:** `permissions-justified`
- **Severity:** `medium`
- **What to look for:** Check `app.json` for `ios.infoPlist` with privacy permissions (NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSLocationWhenInUseUsageDescription, etc.) and `android.permissions` array. Each permission listed should have a clear justification in the app's privacy policy or usage description. Look for excessive permissions (e.g., requesting WRITE_EXTERNAL_STORAGE if not needed, or tracking location when not required).
- **Pass criteria:** Count all declared permissions across both platforms. Each permission has a matching privacy description in iOS (at least 10 characters explaining usage) and a justification for Android. No more than 0 permissions should lack a corresponding usage description. Permissions list is minimal (only requested permissions actually used by the app).
- **Fail criteria:** Missing privacy descriptions for iOS permissions, permissions that appear unnecessary (e.g., location permission in a note-taking app), or overly broad permission set without justification.
- **Skip (N/A) when:** App uses no special permissions (basic camera, microphone, location not required).
- **Cross-reference:** The App Store Privacy & Data audit (`app-store-privacy-data`) provides a deeper analysis of privacy declarations and App Tracking Transparency compliance.
- **Detail on fail:** `"Camera permission requested but no usage description (NSCameraUsageDescription) in Info.plist"` or `"App requests both READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE but only displays images (read-only)"`
- **Remediation:** App stores scrutinize permission requests. Justify and minimize permissions:
  1. For iOS, add to app.json:
     ```json
     "ios": {
       "infoPlist": {
         "NSCameraUsageDescription": "We use your camera to capture photos for...",
         "NSPhotoLibraryUsageDescription": "We need access to your photo library to...",
         "NSLocationWhenInUseUsageDescription": "We use your location to find nearby..."
       }
     }
     ```
  2. For Android, in app.json or AndroidManifest.xml:
     ```json
     "android": {
       "permissions": ["android.permission.CAMERA", "android.permission.ACCESS_FINE_LOCATION"]
     }
     ```
  3. Only request permissions your app actually uses
  4. Request permissions at runtime (not just manifest declaration)
  5. Explain why each permission is needed in your app's privacy policy

---

## External references

- cwe CWE-272
- gdpr Art. 5(1)(c)
- external apple-privacy-permission-usage — https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/requesting_access_to_protected_resources
- external android-permissions-overview — https://developer.android.com/guide/topics/permissions/overview

Taxons: regulatory-conformance, privacy-consent

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