Skip to content

fix: [SDK-3475] restrict notification component exports#2659

Open
fadi-george wants to merge 3 commits into
mainfrom
fadi/sdk-3475
Open

fix: [SDK-3475] restrict notification component exports#2659
fadi-george wants to merge 3 commits into
mainfrom
fadi/sdk-3475

Conversation

@fadi-george

@fadi-george fadi-george commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Description

One Line Summary

Restrict OneSignal notification components that do not need external app access to non-exported Android components.

Details

Motivation

Android security scanners flag several OneSignal notification components as exported without a guarding permission. The affected SDK-owned notification open, dismiss, boot restore, and upgrade restore components are invoked by app-created PendingIntents or protected system broadcasts, so they should not be externally launchable by arbitrary apps.

Scope

This updates the notifications module manifest only. FCMBroadcastReceiver remains exported because it is the FCM entry point and remains protected by com.google.android.c2dm.permission.SEND. NotificationOpenedActivityHMS also remains exported because HMS Core launches it cross-UID for Huawei notification opens. The legacy OEM QUICKBOOT_POWERON action was removed from BootUpReceiver because it is not delivered to a non-exported receiver.

Testing

Unit testing

No new unit tests were added because this is a manifest-only component exposure change.

Manual testing

Automated verification run locally:

  • ./gradlew :OneSignal:notifications:spotlessXmlCheck :OneSignal:notifications:processDebugManifest :OneSignal:notifications:processReleaseManifest :OneSignal:notifications:assembleRelease
  • Inspected onesignal/notifications/build/outputs/aar/notifications-release.aar and confirmed the affected components are packaged with the intended android:exported values, NotificationOpenedActivityHMS remains exported, FCMBroadcastReceiver remains exported with com.google.android.c2dm.permission.SEND, and QUICKBOOT_POWERON is no longer present.
  • ./gradlew :OneSignal:notifications:testDebugUnitTest

Device smoke testing has not been run yet. Recommended follow-up coverage: notification open, action button open, dismiss handling, boot restore, package upgrade restore, and HMS notification open.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
    • If it is hard to explain how any codes changes are related to each other then it most likely needs to be more than one PR
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
    • Simplify with less code, followed by splitting up code into well named functions and variables, followed by adding comments to the code.
  • I have reviewed this PR myself, ensuring it meets each checklist item
    • WIP (Work In Progress) is ok, but explain what is still in progress and what you would like feedback on. Start the PR title with "WIP" to indicate this.

Made with Cursor

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

📊 Diff Coverage Report

✓ Coverage check passed (no source files changed)

📥 View workflow run

@fadi-george

Copy link
Copy Markdown
Contributor Author

@claude[agent] review

@fadi-george

Copy link
Copy Markdown
Contributor Author

@claude review

Comment thread OneSignalSDK/onesignal/notifications/src/main/AndroidManifest.xml

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HMS regression from the prior revision is fixed; remaining nit on QUICKBOOT_POWERON is left as an inline comment for the author to consider.

Extended reasoning...

Overview

This is a manifest-only PR that flips six notification components in the notifications module from android:exported="true" to android:exported="false" to satisfy an Android security scanner finding. The single touched file is OneSignalSDK/onesignal/notifications/src/main/AndroidManifest.xml. The PR scope is narrow and well-described.

Security risks

The PR itself is a defensive hardening change (tightening component visibility). The risk profile is the inverse of typical PRs: the danger is not that the change introduces an exploit, but that it severs a legitimate cross-UID launch path. The prior revision did exactly that for NotificationOpenedActivityHMS, and was corrected in commit 22e4d2d to keep that activity exported. The remaining cross-UID concern is the QUICKBOOT_POWERON action on BootUpReceiver, which the bug hunter has flagged as a nit-level inline comment.

Level of scrutiny

Low–medium. Manifest-only, six lines changed, fully reversible, and the externally-launched HMS entry point has already been re-exported after my prior review. The pattern (security-scanner-driven export tightening) is well-understood and the other five components are safe (PendingIntent-driven or protected broadcasts).

Other factors

The author has demonstrated responsiveness — my previous critical finding on HMS was addressed in a follow-up commit. The remaining QUICKBOOT_POWERON finding is genuinely minor: it affects a small population of legacy HTC Sense / older Lenovo / older Samsung quick-power-on devices on API 21–25, only the quickboot fast-resume path (full-reboot restore via BOOT_COMPLETED is unaffected since it is a protected broadcast). Given the negligible 2026 impact and the trivial nature of the rest of the diff, this is approvable; the author can decide whether to drop the now-unreachable QUICKBOOT_POWERON filter action as documented cleanup.

Comment thread OneSignalSDK/onesignal/notifications/src/main/AndroidManifest.xml
@fadi-george

Copy link
Copy Markdown
Contributor Author

@claude review

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — both previously flagged issues have been resolved: NotificationOpenedActivityHMS remains exported="true" (preserving the HMS Core cross-UID launch path), and the unreachable QUICKBOOT_POWERON action was removed from BootUpReceiver now that it's non-exported.

What was reviewed: the full manifest diff restricting six notification components to non-exported, verifying each is only invoked via internal PendingIntent or protected system broadcasts (BOOT_COMPLETED, MY_PACKAGE_REPLACED); confirmed FCMBroadcastReceiver and NotificationOpenedActivityHMS correctly remain exported for their external entry-point roles.

Extended reasoning...

Overview

This PR modifies a single file, OneSignalSDK/onesignal/notifications/src/main/AndroidManifest.xml, restricting android:exported to false on six notification components (NotificationDismissReceiver, BootUpReceiver, UpgradeReceiver, NotificationOpenedActivity, NotificationOpenedActivityAndroid22AndOlder) that don't require external app invocation, in response to security scanner findings. FCMBroadcastReceiver and NotificationOpenedActivityHMS are intentionally left exported since they are legitimate external entry points (FCM and HMS Core respectively).

Security risks

This is a security-hardening change with no negative security risk itself — it reduces attack surface by preventing arbitrary third-party apps from directly invoking OneSignal's internal notification-handling components. The main risk was functional regression (breaking legitimate external invocation paths), not a new vulnerability.

Level of scrutiny

I previously flagged two functional regressions in this PR across earlier runs: (1) NotificationOpenedActivityHMS being set non-exported would have broken Huawei HMS notification opens (cross-UID launch from HMS Core), and (2) BootUpReceiver retaining the QUICKBOOT_POWERON action while becoming non-exported would leave that action silently unreachable on legacy OEM devices. Both have since been fixed in dedicated follow-up commits (a64e1e0 and 2784275), confirmed by re-reading the current manifest on disk, which matches the PR diff exactly. No new bugs were found by the bug hunting system this run.

Other factors

The change is manifest-only, mechanical in nature (flipping boolean attributes and removing one dead intent-filter action), and the author has done reasonable manual verification (inspecting the built AAR for exported flags and re-running the relevant Gradle tasks). Given both substantive concerns from earlier reviews are now resolved and the remaining change is narrow and well-understood, I'm comfortable approving.

@abdulraqeeb33 abdulraqeeb33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure to test this in browser stack on a real device.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — the previously flagged QUICKBOOT_POWERON issue has been resolved by removing that now-unreachable action from BootUpReceiver's intent-filter, and NotificationOpenedActivityHMS remains exported="true" as required for HMS Core's cross-UID launch. No new bugs found this run.

Extended reasoning...

Overview

This is a follow-up review after the author addressed prior feedback in commit a92d753. The PR restricts six OneSignal-owned notification components (dismiss receiver, boot/upgrade receivers, two notification-open activities) to android:exported="false", since they are only invoked via app-created PendingIntents or protected system broadcasts (BOOT_COMPLETED, MY_PACKAGE_REPLACED). FCMBroadcastReceiver and NotificationOpenedActivityHMS are correctly left exported since they are legitimately launched cross-UID (FCM via a permission guard, HMS Core via explicit component name from the backend payload).

Resolution of prior findings

  • The earlier concern about NotificationOpenedActivityHMS being flipped to non-exported does not apply to the current diff/state — it remains exported="true", matching the PR description and verified against the current manifest in the repo.
  • The QUICKBOOT_POWERON concern (a legacy OEM broadcast not in the protected-broadcast list, which would have become unreachable on a non-exported receiver) was fixed by removing that action from BootUpReceiver's intent-filter, leaving only BOOT_COMPLETED (a protected broadcast delivered from system_server, safe on a non-exported receiver).

Security risks

None beyond the intended effect of the PR: reducing the externally-launchable attack surface of these components, which is a security improvement. No auth/crypto logic is touched.

Level of scrutiny

Low-to-moderate. This is a single manifest file change with narrow, well-understood Android component-export semantics. The remaining components (NotificationDismissReceiver, NotificationOpenedActivity, NotificationOpenedActivityAndroid22AndOlder, UpgradeReceiver) are only invoked in-app via PendingIntent or via protected system broadcasts, both of which are unaffected by exported=false.

Other factors

Author re-ran the manifest processing and AAR inspection to confirm the intended exported values and confirmed unit tests pass. Both issues raised on the previous round have been directly addressed with a clear explanation in the follow-up commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants