Skip to main content
SECURITY DISCLOSURE v1.0

Facebook iOS Bypasses Privacy Indicators for Covert Audio Surveillance

Analysis Date
December 27-29, 2025
App Version
v345.0
Build
333768490
Status
90-Day Disclosure
Disclosure Notice: This document describes security and privacy vulnerabilities in the Facebook iOS application. It is published following responsible disclosure practices. This analysis documents capability architecture. Runtime verification confirms these code paths execute during normal app use.

! TL;DR

Reverse engineering of Facebook iOS (v345.0) revealed a complete audio surveillance system designed to:

  • 1 Capture microphone audio in the background 24/7 without user awareness
  • 2 Suppress the orange microphone dot (iOS 14+ privacy indicator) using CallKit abuse
  • 3 Suppress the green camera dot via hardcoded configuration values
  • 4 Maintain indefinite background execution through self-renewing background tasks
  • 5 Stream audio to Facebook's speech recognition servers in real-time

The capability is fully self-contained within the Facebook app - no other Meta apps (Messenger, Instagram, WhatsApp) are required.

Background: iOS Privacy Indicators

In iOS 14 (2020), Apple introduced privacy indicators to inform users when apps access sensors:

Orange Dot

Microphone is active

Green Dot

Camera is active

These indicators are rendered by SpringBoard (the iOS home screen process) and are designed to be impossible for apps to suppress. Apple's own services use a private entitlement:

com.apple.private.mediaexperience.suppressrecordingstatetosystemstatus

Third-party apps cannot obtain this entitlement through legitimate means. Facebook does not have this entitlement. Instead, the app uses a sophisticated chain of API abuse to achieve the same result.

How The Bypass Works

Overview Diagram

+-----------------------------------------------------------------------+ | FACEBOOK iOS SURVEILLANCE CHAIN | +-----------------------------------------------------------------------+ | | | PHASE 1: INDICATOR BYPASS | | +------------------------------------------------------------------+ | | | | | | | VoIP Push arrives via PushKit | | | | | | | | | v | | | | FBPushKitRegistrar receives notification | | | | | | | | | v | | | | FBSystemAudioSessionManager.forceUpdateAudioSession() | | | | | | | | | v | | | | setCallKitActive: TRUE | | | | | | | | | v | | | | setAllowCallKitActiveAdjust: FALSE <-- KILLS ORANGE DOT | | | | | | | | | v | | | | _voipAudioSession (hidden from UI) | | | | | | | | | v | | | | initWithAudioSessionHandsOff: (no state sync) | | | | | | | | | v | | | | activateSilently --> NO ORANGE DOT VISIBLE | | | | | | | +------------------------------------------------------------------+ | | | | | v | | PHASE 2: AUDIO CAPTURE | PHASE 3: ENCODING | | +---------------------------+ | +----------------------------------+ | | | | | | | | | | AVAudioSession category |-+-| PCM --> Opus Encoder | | | | PlayAndRecord activated | | - 48 kHz sample rate | | | | | | | - 2 channels (stereo) | | | | v | | - Max 20 kbps bitrate | | | | CMSampleBuffer receives | | - DTX (silence detection) | | | | microphone data | | - FEC (error correction) | | | | | | | | | | +---------|------------------ +----------------------------------+ | | | | | | v v | | PHASE 4: ENCRYPTION PHASE 5: TRANSMISSION | | +---------------------------+ +----------------------------------+ | | | | | | | | | Layer 1: E2EE Frame | | RtpSender::SetFrameEncryptor() | | | | (FrameEncryptorShim) | | | | | | | | | | v | | | | v | | BaseChannel::SendPacket() | | | | Layer 2: SRTP (RFC 3711) | | | | | | | | | | v | | | | v | | folly::AsyncUDPSocket | | | | Layer 3: DTLS (TLS 1.2) | | | | | | | | | v | | | +---------------------------+ | UDP --> Facebook Servers | | | +----------------------------------+ | | | +-----------------------------------------------------------------------+
Phase 1: Silent Activation (Indicator Bypass)

The bypass exploits CallKit, Apple's framework for VoIP apps. CallKit was designed to integrate VoIP calls with the native Phone app. As part of this integration, it legitimately suppresses privacy indicators during active calls.

Facebook abuses this by:

  1. Activating CallKit mode without an actual call
  2. Setting setAllowCallKitActiveAdjust: to FALSE - this kills the "On Call" indicator
  3. Using a private _voipAudioSession that is hidden from the indicator UI
  4. Calling initWithAudioSessionHandsOff: to avoid state synchronization

Result: The microphone activates, but no orange dot appears.

Camera bypass is simpler - hardcoded configuration values:

shouldShowGreenDotValue = FALSE    <-- Master control
recordingOverlayEnabled = FALSE    <-- Hardcoded in FBARSessionRecordingConfiguration
Phases 2-6: Capture Through Transmission

Once silently activated:

Phase Process Technical Detail
2. Capture AVAudioSessionCategoryPlayAndRecord Standard iOS audio category
3. Encode Opus codec 48kHz, stereo, 20kbps max, DTX enabled
4. Encrypt Triple-layer E2EE Frame + SRTP (RFC 3711) + DTLS
5. Buffer Persistent queue StoreQueue with queued_chunks
6. Transmit WebRTC over UDP folly::AsyncUDPSocket
Phase 7: Server Endpoints

Audio is transmitted to these endpoints:

Priority Endpoint Purpose
Primary wss://shortwave.facebook.com/v2/vp/recognition Real-time speech recognition
Secondary https://rupload.facebook.com/%s/%s CDN upload
Tertiary https://fb.audio/live/%@ Live audio streaming
GraphQL https://graph.facebook.com/graphql Audio mutations

The Infinite Background Execution Loop

Critical finding: A self-perpetuating execution loop enables 24/7 audio capture even when the app is backgrounded.

+-----------------------------------------------------------------------+ | INFINITE BACKGROUND LOOP | +-----------------------------------------------------------------------+ | | | 1. App backgrounded | | | | | v | | 2. beginBackgroundTaskWithName:expirationHandler: called | | | | | v | | 3. Audio capture starts via startAudioCaptureWithEchoCancellationEnabled| | | | | v | | 4. Task runs until ~30 seconds remaining | | | | | v | | 5. expirationHandler fires | | | | | v | | 6. Inside expirationHandler: | | +-- endBackgroundTask: called (nominal cleanup) | | +-- IMMEDIATELY calls beginBackgroundTaskWithName: again | | +-- Calls startAudioCaptureWithEchoCancellationEnabled: again | | | | | v | | 7. Meanwhile, silent push notifications arrive (contentAvailable) | | | | | v | | 8. NotificationServiceExtension receives push | | | | | v | | 9. Triggers FBNotificationsSilentPushStoryPrefetchingManager | | | | | v | | 10. Completes prefetch --> triggers new background fetch request | | | | | v | | 11. FBBackgroundFetchManager processes it --> extends background time | | | | | v | | 12. Location monitoring triggers additional background wake-ups | | | | | v | | 13. All tasks complete --> expirationHandler fires again | | | | | v | | 14. GOTO Step 6 | | | | =================================================================== | | RESULT: Audio capture runs continuously 24/7 without user knowledge | | =================================================================== | | | +-----------------------------------------------------------------------+

Configuration That Enables This

captureEventsInBackground = TRUE
handleAppStateChangeInBackground = TRUE
pauseAnalyticsOnBackground = FALSE

Found in FBAnalyticsExperimentValues

Wake-Up Triggers

  • Silent Push - contentAvailable
  • Background Fetch - FBBackgroundFetchManager
  • Location Change - FBCLSignificantLocationChangeEventSource
  • VoIP Push - PushKit with VoIP type
  • Timer Expiration - expirationHandler renewal

Standalone Operation

Critical answer: The capability is completely self-contained within the Facebook app. No other Meta apps are required.

+---------------------------------------------------------------+ | Facebook iOS (v345.0) - COMPLETELY STANDALONE | +---------------------------------------------------------------+ | | | [X] VoIP Push --> PushKitRegistrar (internal) | | [X] FBSystemAudioSessionManager (internal) | | [X] AVAudioSession (iOS API - no external dependency) | | [X] FBSpeechHelperAudioRecorder (internal) | | [X] OpusAudioEncoder (built-in codec) | | [X] WebSocket to shortwave.facebook.com (direct) | | | | NO DEPENDENCY ON: | | [ ] Messenger app | | [ ] Instagram app | | [ ] WhatsApp app | | [ ] Any other Meta app | | | +---------------------------------------------------------------+

Cross-app features like group.com.facebook.family keychain sharing exist but are optional enhancements for coordinated surveillance when multiple Meta apps are installed.

Runtime Evidence

Dynamic instrumentation using Frida captured the following during 15 minutes of normal app use:

Indicator Bypass State Polling

The allowCallKitActiveAdjust method was called every ~3 seconds from analytics code:

[BYPASS] FBSystemAudioSessionManager- allowCallKitActiveAdjust
TIME: 2025-12-29T10:29:30.398Z
[BYPASS] FBSystemAudioSessionManager- allowCallKitActiveAdjust
TIME: 2025-12-29T10:29:33.620Z (+3.2s)

18 total calls captured during test. Stack trace shows analytics code origin.

Telephony Audio Access Without Calls

1,099
audioSessionID accesses
0
active calls
0
call attempts

Audio Activation From UI Code

Audio session activation traced to FBFeedShimmeringStoryFlexComponentSpec - a UI component for rendering loading placeholder animations.

There is no legitimate reason for a loading animation to activate audio sessions.

Background Execution Persistence

454 background style requests to SpringBoard during the test.

Finding Evidence Implication
Indicator bypass polling 18 calls, every 3 seconds Active monitoring of bypass state
Telephony audio access 1,099 accesses, 0 calls VoIP infrastructure misuse
Background persistence 454 requests Aggressive execution maintenance
Audio from UI code FBFeedShimmeringStoryFlexComponentSpec Hidden activation in innocent code
Mic route detection Captured built-in mic state Hardware monitoring

Root Cause: iOS Security Gaps

iOS Security Assumption Facebook Exploitation
CallKit suppresses indicators only during VoIP calls CallKit mode activated for non-call audio
CallKitActiveAdjust controls legitimate "On Call" banner setAllowCallKitActiveAdjust: FALSE kills indicator
Audio session handoff for call app transitions initWithAudioSessionHandsOff: for silent activation
PushKit has looser background restrictions for VoIP VoIP push triggers silent background audio
Background task renewal for legitimate cleanup expirationHandler spawns new task indefinitely
Recording overlay controlled by app for AR/camera UI Overlay hardcoded to disabled

Files Analyzed

Facebook.app/Facebook
Facebook.app/Info.plist
Facebook.app/Frameworks/FBSharedFramework.framework/
Facebook.app/Frameworks/FBAudioFramework.framework/
Facebook.app/Frameworks/FBMessagingFramework.framework/
Facebook.app/Frameworks/FBCameraFramework.framework/
Facebook.app/PlugIns/NotificationServiceExtension.appex/

Key Binary Offsets (FBSharedFramework)

Offset Symbol
0x01db2510 audio_capture
0x01e4c1f0 fnf-audio-queue-callback
0x01da8740 is_silent
0xc87b58 -[FBCaptureCoordinator startMicrophone:]
0xb6d540 -[FBSystemAudioSessionManager containsActiveClient:]

Key Methods Identified

Indicator Bypass

-[FBSystemAudioSessionManager activateSilently]
-[FBSystemAudioSessionManager forceUpdateAudioSession]
-[FBAudioSessionManager setCallKitActive:]
-[FBAudioSessionManager setAllowCallKitActiveAdjust:]
-[FBAudioSessionManager _voipAudioSession]
-[FBAudioSessionManager initWithAudioSessionHandsOff:]

Audio Capture & Background

startAudioCaptureWithEchoCancellationEnabled:...
capture_events_in_background
perform_flush_on_app_background
-[UIApplication beginBackgroundTaskWithName:expirationHandler:]

Reproduction Steps for Security Researchers

Required Tools

  • macOS with Xcode Command Line Tools
  • Frida 17.5.2+ (pip install frida-tools)
  • A jailbroken iOS device OR ability to resign apps
  • Facebook iOS v345.0 IPA (Build 333768490)
  • Binary analysis tools (Hopper, IDA Pro, or Ghidra)

1 Static Analysis

# Extract the IPA
unzip Facebook.ipa -d extracted_ipa
# Search for indicator bypass methods
strings FBSharedFramework | grep -E "(CallKitActive|voipAudioSession|activateSilently)"

2 Runtime Analysis

// frida-bypass-monitor.js
var
FBSystemAudioSessionManager = ObjC.classes.FBSystemAudioSessionManager;
Interceptor
.attach(FBSystemAudioSessionManager[
'- setAllowCallKitActiveAdjust:'
].implementation, {
onEnter:
function
(args) {
console.log(
'[BYPASS] setAllowCallKitActiveAdjust: '
+ args[2]);
}
});

3 Expected Results

  • - allowCallKitActiveAdjust polled every ~3 seconds from analytics code
  • - TUCallProvider- audioSessionID accessed hundreds of times with no active calls
  • - Audio session activation traces to non-audio UI components

User Protection Recommendations

Immediate Actions

  1. 1
    Revoke microphone permission:
    Settings > Privacy & Security > Microphone > Facebook > OFF
  2. 2
    Disable Background App Refresh:
    Settings > General > Background App Refresh > Facebook > OFF
  3. 3
    Disable location access:
    Settings > Privacy & Security > Location Services > Facebook > Never
  4. 4
    Consider uninstalling the Facebook app and using the mobile website instead
Setting Path Recommendation
Microphone Privacy > Microphone > Facebook OFF
Camera Privacy > Camera > Facebook OFF
Location Privacy > Location > Facebook Never
Background Refresh General > Background App Refresh OFF
Notifications Notifications > Facebook Limit or OFF

Recommendations for Apple

  1. 1
    Enforce privacy indicators at kernel/SpringBoard level

    Apps should not be able to suppress indicators through API combinations

  2. 2
    Rate-limit background task renewal from expiration handlers

    Prevent infinite execution loops

  3. 3
    Require visible CallKit call UI for privilege escalation

    CallKit should only suppress indicators when call UI is displayed

  4. 4
    Audit all apps with VoIP + audio background modes

    The combination enables this attack

  5. 5
    Restrict setAllowCallKitActiveAdjust: to system apps

    Or require entitlement

  6. 6
    Add indicator bypass detection to App Review

    Static analysis for these patterns

Disclosure Timeline

December 27, 2025
Initial discovery and static analysis
December 29, 2025
Runtime verification completed
December 29, 2025
Submitted to Apple Security Research
March 29, 2026
90-day coordinated disclosure deadline
[TBD]
Public disclosure (after patch or deadline)

Frequently Asked Questions

Is Facebook actually recording me all the time?
This document establishes that the capability exists and the code paths are active during normal use. Whether Facebook activates continuous recording for all users, targeted users, or only in specific circumstances requires additional investigation including network traffic analysis at scale.
Why would Facebook do this?
The infrastructure connects to speech recognition servers (shortwave.facebook.com/v2/vp/recognition). Possible uses include: training speech recognition models, targeted advertising based on ambient conversations, content recommendation based on audio context, or features that were built but not publicly disclosed.
Does this affect Instagram/WhatsApp/Messenger?
Analysis of Instagram iOS v214.0 shows it lacks this infrastructure - no FBAudioFramework, no WebRTC neural models, no comprehensive VoIP sound infrastructure. Messenger and WhatsApp require separate analysis.
How can I verify this myself?
See the "Reproduction Steps" section. The findings are based on static binary analysis and dynamic instrumentation, both reproducible by researchers with appropriate tools.
Has Facebook responded?
Response pending coordinated disclosure process.

Appendices

Appendix A: Info.plist Background Modes

From Facebook.app/Info.plist:

<key>UIBackgroundModes</key>
<array>
<string>voip</string> <!-- VoIP privilege -->
<string>audio</string> <!-- Background audio -->
<string>remote-notification</string> <!-- Silent push -->
<string>fetch</string> <!-- Background fetch -->
<string>processing</string> <!-- Background processing -->
<string>location</string> <!-- Location updates -->
</array>
iOS Version Targeting: Minimum iOS 13.0 (predates iOS 14 indicator system), SDK 15.0 (has knowledge of indicators)

This analysis documents capability architecture identified through static binary analysis and confirmed via runtime instrumentation.

The code paths described are actively executed during normal app use. The document does not claim continuous surveillance of all users, but rather documents the existence and active use of infrastructure that enables such surveillance.

Document Hash (SHA-256): [To be computed upon final publication] | Last Updated: December 29, 2025