Over-permissioned apps are a primary reason users uninstall or leave one-star reviews. Under GDPR Art. 5(1)(c) (data minimisation) and CCPA §1798.100, you may only collect data necessary for declared purposes — declaring a CAMERA permission when no camera feature exists is both a regulatory red flag and an app store rejection risk. Apple's permission best-practices guidelines make explicit that reviewers check for permissions without corresponding feature code. On Android, Google Play surfaces declared permissions on your store listing; users see every permission before they download. Unused permissions also expand your attack surface: a compromised SDK can silently exploit a declared permission even if your own code never calls it.
Critical because an unused declared permission grants third-party SDKs a silent attack vector and exposes the developer to GDPR data-minimisation violations and app store rejection without any corresponding user benefit.
Audit every permission in app.json against your active feature inventory, then remove any with no live code path. For location, always prefer the narrowest scope that works.
{
"expo": {
"ios": {
"infoPlist": {
"NSCameraUsageDescription": "Camera access is needed for video calls",
"NSLocationWhenInUseUsageDescription": "Location shows nearby content while the app is open"
}
},
"android": {
"permissions": [
"android.permission.CAMERA",
"android.permission.ACCESS_FINE_LOCATION"
]
}
}
}
Delete any entry whose usage description cannot be traced to a concrete screen or feature. For location, replace LOCATION_ALWAYS with LOCATION_WHEN_IN_USE unless a background-tracking feature genuinely requires it.
ID: mobile-permissions-privacy.permission-requests.necessary-permissions
Severity: critical
What to look for: Enumerate all declared permissions in app.json (iOS infoPlist and Android permissions array) and all permission request calls in code. For each permission, classify whether an active feature uses it. Report: "X permissions declared, Y actively used."
Pass criteria: At least 100% of declared/requested permissions have an active feature that uses them. No unused or placeholder permissions are present. Report the count even on pass: "All N declared permissions are actively used."
Fail criteria: App declares or requests permissions that are not used (e.g., contacts permission but no contacts feature, camera permission but no camera screens). OR permission scope is broader than necessary (e.g., always location when only when-in-use is needed). Do NOT pass when permissions exist in app.json but no corresponding feature code can be found.
Skip (N/A) when: Never — all apps should minimize permission requests.
Detail on fail: List the unnecessary permissions and quote the actual declaration. Example: "app.json includes 'CAMERA' permission but no camera feature exists in the app" or "location permission requests 'always' but feature only needs 'when-in-use'"
Cross-reference: For app store review risks from unnecessary permissions, the App Store Review Blockers audit covers permission-related rejection reasons.
Remediation: Permissions are trust signals — users are more likely to grant apps that request only what they genuinely need. Review your app.json permissions array and permission request code:
{
"app.json": {
"ios": {
"infoPlist": {
"NSCameraUsageDescription": "Camera access needed for video calls",
"NSLocationWhenInUseUsageDescription": "Location needed to show nearby content"
}
},
"android": {
"permissions": [
"android.permission.CAMERA",
"android.permission.ACCESS_FINE_LOCATION"
]
}
}
}
Keep only permissions your app actively uses. For location, prefer when-in-use over always unless your app genuinely needs background location.