Common Permission Escalation in Food Delivery Apps: Causes and Fixes
Permission escalation occurs when an app requests a dangerous permission (e.g., READ_PHONE_STATE, ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE) that it does not actually need, then later grants itself
Permission Escalation in Food Delivery Apps
1. Technical Root Causes
Permission escalation occurs when an app requests a dangerous permission (e.g., READ_PHONE_STATE, ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE) that it does not actually need, then later grants itself additional privileges through a mis‑configured manifest or runtime request flow. In food delivery apps the most common culprits are:
| Root cause | Why it happens in food delivery | Typical code pattern |
|---|---|---|
| Over‑broad manifest entries | Developers add ACCESS_FINE_LOCATION to enable “nearby restaurant” suggestions, but also need it for background tracking of driver location. | (declared once, used everywhere) |
| Runtime permission conflation | A single requestPermissions() call may request multiple permissions, and the app assumes all are granted even if only a subset is required for a specific feature (e.g., camera for scanning QR codes). | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE}, 100); |
| Implicit permission inheritance | Libraries (e.g., third‑party SDKs for payment or analytics) declare their own dangerous permissions. If the app does not filter them, the final APK ends up with more permissions than intended. | Including a SDK that adds READ_CONTACTS for “invite friends” feature. |
| Improper permission check after grant | The app checks PackageManager.PERMISSION_GRANTED once at install time, then later assumes the permission remains granted after an OS‑initiated revocation (e.g., after a security patch). | if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { … } |
These technical oversights are amplified in food delivery apps because they rely heavily on real‑time location, camera, microphone, and phone state to deliver a seamless experience (e.g., tracking driver ETA, scanning QR codes for order pickup, auto‑filling payment details).
2. Real‑World Impact
| Impact area | Description | Business consequence |
|---|---|---|
| User complaints | Users notice that an app suddenly asks for contacts or SMS after installing a minor update, leading to distrust and negative reviews. | 1‑2 star ratings, higher churn. |
| Store ratings | Restaurants receive complaints when the app misbehaves (e.g., crashes when location permission is denied), causing them to rate the platform lower. | Reduced partnership renewals, revenue dip. |
| Revenue loss | Permission‑related crashes or blocked features (e.g., camera not available for QR scanning) interrupt the order flow, resulting in abandoned carts. | Direct reduction in order value and commission. |
| Regulatory risk | Excessive data collection (e.g., reading SMS for OTP auto‑fill) may violate privacy regulations (GDPR, CCPA). | Fines, legal overhead, brand damage. |
A concrete example: a major food delivery platform rolled out a “track driver in real time” feature that required ACCESS_FINE_LOCATION and FOREGROUND_SERVICE. The manifest was updated once, but the app also requested READ_PHONE_STATE for “detect incoming calls while delivering”. Users reported the app silently making phone calls, leading to a 12 % drop in app store rating within a week and a subsequent patch that removed the unnecessary permission.
3. Manifestation Examples (5‑7)
- Background location tracking without user consent – The app requests
ACCESS_FINE_LOCATIONfor “find nearby restaurants”, then continues to receive location updates while the app is in the background, draining battery and raising privacy flags. - Camera permission used for QR scanning but also for taking photos of the delivered food – The same
CAMERApermission is granted, allowing the app to capture images without explicit user intent. - SMS/Call permission for automatic OTP retrieval – The app adds
READ_SMSandREAD_PHONE_STATEto auto‑fill verification codes, but the permission also enables the app to read incoming calls, a clear escalation. - Microphone access for “voice order” feature that is never used – The app declares
RECORD_AUDIOfor a voice command module that was removed in a previous release, yet the permission remains. - Storage permission for caching menus that is later abused to read private files –
WRITE_EXTERNAL_STORAGEis granted for saving temporary menu images; a malicious component later reads other app data from the same storage location. - Location + Bluetooth permission for indoor navigation – The app requests both
ACCESS_FINE_LOCATIONandBLUETOOTH_CONNECTto map restaurant interiors, but Bluetooth can be leveraged to track user movement across venues. - Accessibility service permission for “screen reader” – The app declares
BIND_ACCESSIBILITY_SERVICEto support screen‑reader users, but the service can be abused to overlay UI elements, causing phishing‑style attacks.
4. Detection
| Technique | Tools / How‑to | What to look for |
|---|---|---|
| Static manifest analysis | Android Studio’s “Analyze > Inspect Code” or grep for entries. | Permissions that are not directly tied to a feature (e.g., READ_PHONE_STATE without a phone‑related UI). |
| Runtime permission audit | Use adb shell pm list permissions -g and adb shell dumpsys package to see which permissions are actually granted at runtime. | Grants that occur after the initial onCreate() without a corresponding user request. |
| Permission usage tracing | Android’s Permission Controller (Android 11+) or third‑party libraries like Permission‑Watcher. | Unexpected permission requests during background services or after a certain screen transition. |
| Automated UI testing | Integrate SUSATest (or similar) to record permission dialogs and verify that only required prompts appear. | False‑positive prompts (e.g., asking for camera when only location is needed). |
| Log‑based monitoring | Instrument code to log onRequestPermissionsResult and onPermissionResult with the permission name and caller activity. | Repeated requests for the same permission across unrelated modules. |
| Security scanning | Run MobSF, QARK, or Checkmarx on the APK. | Manifest over‑declaration, hard‑coded permission strings, or unsafe permission groups. |
Focus on permission‑to‑feature mapping: each requested permission should have a documented justification (e.g., “CAMERA – required for QR‑code scanning at pickup”). Any deviation is a red flag.
5. Fixes (Code‑Level Guidance)
- Trim manifest – Remove any
that is not required for a specific feature. Use feature‑specific permission groups (e.g.,fineLocationonly when GPS is needed).
// Bad
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
// Good – request only when GPS UI is visible
if (hasLocationFeature()) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION);
}
- Scope runtime requests – Request permissions just before they are needed, not at app start.
// Instead of a blanket request in onCreate()
if (needCameraForQr()) {
requestCameraPermission();
}
- Check permission state each time – Do not rely on a one‑time grant; re‑check before using the permission.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Prompt user again or disable location‑based features
}
- Isolate third‑party SDK permissions – Review each SDK’s manifest, and if a SDK adds unwanted permissions, either exclude the SDK or use a wrapper that strips them via
android:extractNativeLibs="false"and customApplicationclass.
- Graceful degradation – When a required permission is denied, disable the related feature rather than crashing.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS)
!= PackageManager.PERMISSION_GRANTED) {
// Show fallback UI: manual OTP entry
}
- Use Android’s permission rationale – Provide a clear
shouldShowRequestPermissionRationalemessage that ties the permission to the concrete user benefit (e.g., “We need location to show nearby restaurants and estimate delivery time”).
6. Prevention
- Feature‑first permission matrix – Create a spreadsheet linking each app feature to the minimal permission set. Enforce this matrix during design reviews.
- CI/CD gate – Add a pre‑merge step that runs a static analysis script (e.g., a Gradle task invoking
android lintwith a custom rule) to flag any permission not present in the matrix. - Automated UI validation – Integrate SUSA or a similar autonomous QA tool to run a suite of flows (login → order → checkout) and assert that only expected permission prompts appear.
- **Regular
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free