Bug Report
Plugin(s)
@capacitor/share 8.0.1
Capacitor Version
Latest Dependencies:
@capacitor/cli: 8.5.1
@capacitor/core: 8.5.1
@capacitor/android: 8.5.1
@capacitor/ios: 8.5.1
Installed Dependencies:
@capacitor/core: 8.4.0
@capacitor/cli: 8.4.0
@capacitor/android: 8.4.0
@capacitor/ios: 8.4.0
Platform(s)
Android
Current Behavior
SharePlugin.load() registers the EXTRA_CHOSEN_COMPONENT broadcast receiver with ContextCompat.RECEIVER_EXPORTED and no permission string or sender check:
https://github.com/ionic-team/capacitor-plugins/blob/main/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java#L44
ContextCompat.registerReceiver(
getContext(),
broadcastReceiver,
new IntentFilter(Intent.EXTRA_CHOSEN_COMPONENT),
ContextCompat.RECEIVER_EXPORTED
);
Because the receiver is exported, any app on the device can broadcast an intent with action Intent.EXTRA_CHOSEN_COMPONENT and overwrite chosenComponent. That value is returned to JS as activityType from Share.share(), so the reported target app can be spoofed.
Impact is low. The field is informational only and nothing else consumes it. Still, static analysis (Veracode) flags it as CWE-926 (Improper Export of Android Application Components), which blocks security sign-off for apps that depend on this plugin.
Expected Behavior
The receiver should only accept the callback from the system chooser. That broadcast is delivered through a PendingIntent created by this app, so it carries the app's own identity and a non-exported receiver will still receive it. The registration should use ContextCompat.RECEIVER_NOT_EXPORTED.
Code Reproduction
Not required to observe the issue; it is visible in the plugin source at the line above. To confirm at runtime, install any second app that sends:
Intent i = new Intent(Intent.EXTRA_CHOSEN_COMPONENT);
i.putExtra(Intent.EXTRA_CHOSEN_COMPONENT, new ComponentName("com.spoofed", "com.spoofed.Activity"));
sendBroadcast(i);
while the Capacitor app is running, then call Share.share() and cancel or complete the share. activityType reflects the spoofed package.
Other Technical Details
Additional Context
Suggested fix, one line:
ContextCompat.RECEIVER_NOT_EXPORTED
If there is concern about OEM or third-party share sheets that fire the broadcast directly rather than through the PendingIntent, an alternative is to keep the receiver exported but include a random nonce as an extra on the PendingIntent and ignore any broadcast that does not echo it back.
Bug Report
Plugin(s)
@capacitor/share 8.0.1
Capacitor Version
Platform(s)
Android
Current Behavior
SharePlugin.load()registers theEXTRA_CHOSEN_COMPONENTbroadcast receiver withContextCompat.RECEIVER_EXPORTEDand no permission string or sender check:https://github.com/ionic-team/capacitor-plugins/blob/main/share/android/src/main/java/com/capacitorjs/plugins/share/SharePlugin.java#L44
Because the receiver is exported, any app on the device can broadcast an intent with action
Intent.EXTRA_CHOSEN_COMPONENTand overwritechosenComponent. That value is returned to JS asactivityTypefromShare.share(), so the reported target app can be spoofed.Impact is low. The field is informational only and nothing else consumes it. Still, static analysis (Veracode) flags it as CWE-926 (Improper Export of Android Application Components), which blocks security sign-off for apps that depend on this plugin.
Expected Behavior
The receiver should only accept the callback from the system chooser. That broadcast is delivered through a
PendingIntentcreated by this app, so it carries the app's own identity and a non-exported receiver will still receive it. The registration should useContextCompat.RECEIVER_NOT_EXPORTED.Code Reproduction
Not required to observe the issue; it is visible in the plugin source at the line above. To confirm at runtime, install any second app that sends:
while the Capacitor app is running, then call
Share.share()and cancel or complete the share.activityTypereflects the spoofed package.Other Technical Details
RECEIVER_EXPORTEDappears to have been chosen to preserve pre-34 behaviour (see Share plugin incompatible with Android 14 #1823, @capacitor/share not work in android 14, capacitor 6 #2068, Android 14 targetted build fails with RECEIVER_EXPORTED variable error #2089).Additional Context
Suggested fix, one line:
If there is concern about OEM or third-party share sheets that fire the broadcast directly rather than through the PendingIntent, an alternative is to keep the receiver exported but include a random nonce as an extra on the PendingIntent and ignore any broadcast that does not echo it back.