Technical guide

How to detect unauthorised microphone access in mobile apps

Detect unauthorised microphone use in your app with Android audit callbacks, recording configuration checks, privacy indicators and the App Privacy Report.

  • Trace the capture

    Follow permission, start trigger, input route, processing and upload before deciding which recording counts as unauthorised.

  • Use platform evidence

    Privacy indicators, Android data access auditing and the iOS App Privacy Report show capture from the operating system's side.

  • Preserve legitimate use

    Calls, assistants, accessories and sensor toggles change what the app hears. Treat them as normal states, not attacks.

To detect unauthorised microphone access in your app, define when capture is allowed, then prove that every recording started from that trigger and went only where it should. On Android, data access auditing reports each microphone operation with a stack trace, and AudioRecordingConfiguration tells you when your capture is silenced. On iOS, AVAudioApplication reports the record permission and the App Privacy Report shows when the app used the microphone. Both systems also show the user an indicator during capture. This guide covers your own app’s capture path, with separate steps for Android and iOS.

Define authorised capture

Draw the real feature first: voice message, support call, voice note or dictation. Mark the start trigger, the selected input, the capture component, any temporary file and the backend request. List every library inside your app that can reach the microphone, including call, analytics and advertising SDKs.

“Unauthorised” then has a precise meaning in your app:

  • capture that starts without the expected user action;
  • capture that continues after the feature ends or the app leaves the foreground;
  • capture by a component that has no purpose on the journey;
  • audio sent to an endpoint the feature does not use.

Each case needs its own test and evidence. A permission grant covers every component in your process, so attribution matters more than the permission state.

What the user and the platform already show

Both platforms make capture visible to the person holding the phone. Your tests should check that what they see matches what the feature intends.

MechanismAndroidiOS
Runtime permissionRECORD_AUDIONSMicrophoneUsageDescription plus the record permission prompt
Capture indicatorStatus bar icon when an app uses the microphone (Android 12 onwards)Orange indicator while the microphone is in use (iOS 14 onwards)
Global switchMicrophone access toggle in Quick Settings and the Privacy screen on supported devices (Android 12 onwards)Per-app microphone switch in Settings
Access historyPrivacy dashboard covering location, camera and microphone (Android 12 onwards)App Privacy Report, past seven days (iOS 15.2 onwards)

An indicator appearing outside the feature is the simplest finding a tester can make. Record it with the screen, the time and the build.

Android: limits and audit

Platform limits that shape your test

  • Background capture. Since Android 9, an app without a visible activity or a foreground service receives silence when it captures audio. A background read that returns real audio means a foreground service is running.
  • Foreground service type. Capturing audio from a foreground service requires the microphone foreground service type. Apps targeting Android 14 must also declare the FOREGROUND_SERVICE_MICROPHONE permission and pass FOREGROUND_SERVICE_TYPE_MICROPHONE to startForeground(). Because RECORD_AUDIO is a while-in-use permission, a microphone foreground service cannot be started while the app is in the background. Review every service that declares this type; each one should map to a feature in your capture diagram.
  • Sensor toggle. When the user turns microphone access off, apps receive silent audio. SensorPrivacyManager.supportsSensorToggle() tells you whether the device offers the toggle, so you can explain silence instead of reporting an error.
  • Shared input. Since Android 10, the system decides which app receives audio when several capture at once. Privileged apps such as the assistant or an accessibility service can share input with your app, and your app can be silenced by a call. Register AudioManager.registerAudioRecordingCallback() and read AudioRecordingConfiguration.isClientSilenced() to record when your capture was silenced.

Attribute each capture

Android 11 (API level 30) added data access auditing. Register an AppOpsManager.OnOpNotedCallback with setOnOpNotedCallback() and log the stack trace in onNoted(). For audio, the operation is OPSTR_RECORD_AUDIO. A capture whose stack trace leads to an SDK rather than your feature code is a finding. Declare an <attribution> tag per feature and use Context.createAttributionContext(), so the record names the part of the app that captured.

iOS: permission, session and report

Every capture needs an NSMicrophoneUsageDescription that states the purpose. From iOS 17, use AVAudioApplication.requestRecordPermission(completionHandler:) to ask and AVAudioApplication.shared.recordPermission to read the state; this replaces the older AVAudioSession record-permission API. Check the state before showing a record button and handle denial with a non-audio alternative.

Treat the audio session as part of the evidence. Observe AVAudioSession.interruptionNotification so a phone call, alarm or Siri request stops and resumes capture in line with the feature’s consent model. After an interruption, require a fresh user action if resuming would surprise the person.

iOS has no in-app audit callback like Android’s, so attribution comes from three sources:

  1. App Privacy Report. On a test device with the report turned on, run one journey and confirm that microphone access appears only while the feature ran. The report also lists the domains the app contacted.
  2. SDK privacy manifests. Compare what each third-party SDK declares in its PrivacyInfo.xcprivacy file with your capture diagram.
  3. Code review of capture call sites. Search the app and its dependencies for AVAudioEngine, AVAudioRecorder and audio unit set-up, and confirm each sits behind the intended trigger.

Run the test

Use dedicated physical devices, a non-production build, a test account and synthetic audio. Simulators are useful for development checks but do not exercise real microphone hardware or indicators.

  1. Record the OS version, device, app build, framework and audio libraries.
  2. Run the journey with permission granted. Confirm the indicator appears only during capture, and collect the Android audit record or the iOS report entry.
  3. Deny the permission, then grant it again in Settings. The app explains the unavailable feature and does not ask repeatedly.
  4. On Android, turn the microphone toggle off and confirm the app reports silence, not a security event.
  5. Send the app to the background during capture and confirm capture stops, unless a declared foreground service is meant to continue.
  6. Repeat with headsets, an external microphone and an incoming call.
  7. Search your controlled backend for uploads outside the feature.

A capture started by injected code looks different from one started by your own SDK: the trigger or stack trace includes code that is not in your build. Otukan detects hooking and tampering in the app process and reports it to your backend, so you can line that evidence up with your own capture records. For audio content checks, see voice and audio injection detection.

Respond in proportion

ScenarioExpected behaviour
Permission denied or sensor toggle offExplain the unavailable function and keep non-audio alternatives
Capture silenced by a call or assistantPause or end the recording; no security finding
Accessory connected or removedRe-establish the intended input
SDK captures without a purposeBlock the release; remove or configure the SDK
Hooking evidence during captureApply the runtime policy for that flow and keep support access

Release checklist

  • Each capture feature has a recorded trigger, input, destination and stop condition.
  • Every Android foreground service with the microphone type maps to a feature.
  • Android test builds log OPSTR_RECORD_AUDIO with stack traces and attribution tags.
  • iOS builds are checked against the App Privacy Report and SDK privacy manifests.
  • Silence, interruptions and sensor toggles produce clear messages, not alerts.
  • Diagnostics never include audio content.

The same method applies to other protected data; see how to detect unauthorised contacts access. The app and backend split is covered on the integration overview.

Further reading

Common questions

  • Does silent audio on Android mean something is wrong?

    Not on its own. Android delivers silence when the user turns microphone access off, when an app captures without a visible activity or foreground service, or when a call silences your capture. Read AudioRecordingConfiguration.isClientSilenced() through AudioManager.registerAudioRecordingCallback() to record it, and explain it rather than raising a security event.

  • What does an Android app need to capture audio from a foreground service?

    The microphone foreground service type. Apps targeting Android 14 must also declare FOREGROUND_SERVICE_MICROPHONE and pass FOREGROUND_SERVICE_TYPE_MICROPHONE to startForeground(). Because RECORD_AUDIO is a while-in-use permission, such a service cannot be started while the app is in the background. Each service should map to a feature in your capture diagram.

  • How do I attribute a microphone capture to the code that started it on Android?

    Use data access auditing, added in Android 11 (API level 30). Register an AppOpsManager.OnOpNotedCallback with setOnOpNotedCallback() and log the stack trace in onNoted() for OPSTR_RECORD_AUDIO. A stack trace leading to an SDK rather than your feature code is a finding, and attribution tags name the capturing feature.

  • Which API should an iOS app use for the record permission?

    From iOS 17, use AVAudioApplication.requestRecordPermission(completionHandler:) to ask and AVAudioApplication.shared.recordPermission to read the state; this replaces the older AVAudioSession record-permission API. Every capture also needs an NSMicrophoneUsageDescription that states the purpose, and denial should lead to a non-audio alternative.

  • Can I test microphone access on a simulator?

    Only for development checks. Simulators do not exercise real microphone hardware or indicators, so tests use dedicated physical devices, a non-production build, a test account and synthetic audio. Record the OS version, device, app build, framework and audio libraries for each run.

Review your audio capture boundary

Tell us your platforms, framework, audio capture flow and main integrity requirement. We never ask for binaries, credentials, voice recordings or production data.

Or request a technical demo