CVE-2022-4903: Exposure of Resource to Wrong Sphere (CWE-668)
value: A vulnerability was found in CodenameOne 7.0.70. It has been classified as problematic. Affected is an unknown function. The manipulation leads to use of implicit intent for sensitive communication. It is possible to launch the attack remotely. The complexity of an attack is rather high. The exploitability is told to be difficult. Upgrading to version 7.0.71 is able to address this issue. The patch is identified as dad49c9ef26a598619fc48d2697151a02987d478. It is recommended to upgrade the affected component. VDB-220470 is the identifier assigned to this vulnerability.
CWE description: The product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource.
CVSS v3 base score: 8.1
Published: 2023-02-10T15:15Z
Repository: https://github.com/codenameone/CodenameOne
Language: Java
Files changed: Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java, Ports/Android/src/com/codename1/impl/android/CodenameOneActivity.java, Ports/Android/src/com/codename1/impl/android/PushNotificationService.java, Ports/Android/src/com/codename1/location/AndroidLocationPlayServiceManager.java, Ports/Android/src/com/codename1/media/BackgroundAudioService.java
Commit date: 2022-04-23 07:50:21 +0300
Commit message: Fixed #3583 Pending Intent vulnerability

Diff: diff --git a/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java b/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java
index 18b5334ce..c6cd7f158 100644
--- a/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java
+++ b/Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java
@@ -773,11 +773,40 @@ public class AndroidImplementation extends CodenameOneImplementation implements
             out.add(cat);
             
         }
         return out.toArray(new PushActionCategory[out.size()]);
     }
-    
+
+    public static PendingIntent createPendingIntent(Context ctx, int value, Intent intent) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            // PendingIntent.FLAG_IMMUTABLE
+            return PendingIntent.getActivity(ctx, value, newIntent, 67108864);
+        } else {
+            return PendingIntent.getActivity(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        }
+    }
+
+    public static PendingIntent getPendingIntent(Context ctx, int value, Intent intent) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            // PendingIntent.FLAG_IMMUTABLE
+            return PendingIntent.getService(ctx, value, newIntent, 67108864);
+        } else {
+            return PendingIntent.getService(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        }
+        PendingIntent.getService
+    }
+
+    public static PendingIntent getBroadcastPendingIntent(Context ctx, int value, Intent intent) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            // PendingIntent.FLAG_IMMUTABLE
+            return PendingIntent.getBroadcast(ctx, value, newIntent, 67108864);
+        } else {
+            return PendingIntent.getBroadcast(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        }
+        PendingIntent.getService
+    }
+
     /**
      * Adds actions to a push notification.  This is called by the Push broadcast receiver probably before 
      * Codename One is initialized
      * @param provider Reference to the app's main class which implements PushActionsProvider
      * @param categoryId The category ID of the push notification.
@@ -809,11 +838,11 @@ public class AndroidImplementation extends CodenameOneImplementation implements
         
         int requestCode = 1;
         for (PushAction action : category.getActions()) {
             Intent newIntent = (Intent)targetIntent.clone();
             newIntent.putExtra("pushActionId", action.getId());
-            PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode++, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+            PendingIntent contentIntent = createPendingIntent(context, requestCode++, newIntent);
             try {
                 int iconId = 0;
                 try { iconId = Integer.parseInt(action.getIcon());} catch (Exception ex){}
                 //android.app.Notification.Action.Builder actionBuilder = new android.app.Notification.Action.Builder(iconId, action.getTitle(), contentIntent);
 
@@ -7091,11 +7120,11 @@ public class AndroidImplementation extends CodenameOneImplementation implements
 
         NotificationManager notificationManager = (NotificationManager) getContext().getSystemService(Activity.NOTIFICATION_SERVICE);
 
         Intent notificationIntent = new Intent();
         notificationIntent.setComponent(activityComponentName);
-        PendingIntent contentIntent = PendingIntent.getActivity(getContext(), 0, notificationIntent, 0);
+        PendingIntent contentIntent = createPendingIntent(getContext(), 0, notificationIntent);
 
 
         NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext())
                 .setContentIntent(contentIntent)
                 .setSmallIcon(id)
@@ -10414,24 +10443,23 @@ public class AndroidImplementation extends CodenameOneImplementation implements
             Intent intent = new Intent(context, BackgroundFetchHandler.class);
             //there is an bug that causes this to not to workhttps://code.google.com/p/android/issues/detail?id=81812
             //intent.putExtra("backgroundClass", getBackgroundLocationListener().getName());
             //an ugly workaround to the putExtra bug 
             intent.setData(Uri.parse("http://codenameone.com/a?" + getBackgroundFetchListener().getClass().getName()));
-            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = getPendingIntent(context, 0,
+                    intent);
             notificationIntent.putExtra(LocalNotificationPublisher.BACKGROUND_FETCH_INTENT, pendingIntent);
 
         } else {
             contentIntent.setData(Uri.parse("http://codenameone.com/a?LocalNotificationID="+Uri.encode(notif.getId())));
         }
-        PendingIntent pendingContentIntent = PendingIntent.getActivity(getContext(), 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent pendingContentIntent = createPendingIntent(getContext(), 0, contentIntent);
 
         notificationIntent.putExtra(LocalNotificationPublisher.NOTIFICATION_INTENT, pendingContentIntent);
 
 
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent pendingIntent = getBroadcastPendingIntent(getContext(), 0, notificationIntent);
 
         AlarmManager alarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
         if (BACKGROUND_FETCH_NOTIFICATION_ID.equals(notif.getId())) {
             alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, firstTime, getPreferredBackgroundFetchInterval() * 1000, pendingIntent);
         } else {
@@ -10460,11 +10488,11 @@ public class AndroidImplementation extends CodenameOneImplementation implements
 
     public void cancelLocalNotification(String notificationId) {
         Intent notificationIntent = new Intent(getContext(), LocalNotificationPublisher.class);
         notificationIntent.setAction(getContext().getApplicationInfo().packageName + "." + notificationId);
 
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent pendingIntent = getBroadcastPendingIntent(getContext(), 0, notificationIntent);
         AlarmManager alarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
         alarmManager.cancel(pendingIntent);
     }
 
     static Bundle createBundleFromNotification(LocalNotification notif){
diff --git a/Ports/Android/src/com/codename1/impl/android/CodenameOneActivity.java b/Ports/Android/src/com/codename1/impl/android/CodenameOneActivity.java
index a8eadf78d..0eacebc60 100644
--- a/Ports/Android/src/com/codename1/impl/android/CodenameOneActivity.java
+++ b/Ports/Android/src/com/codename1/impl/android/CodenameOneActivity.java
@@ -426,19 +426,19 @@ public class CodenameOneActivity extends Activity {
     }
 
     public void registerForPush(String key) {
         Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
         registrationIntent.setPackage("com.google.android.gms");
-        registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // boilerplate
+        registrationIntent.putExtra("app", AndroidImplementation.getBroadcastPendingIntent(this, 0, new Intent())); // boilerplate
         registrationIntent.putExtra("sender", key);
         startService(registrationIntent);
     }
 
     public void stopReceivingPush() {
         Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
         unregIntent.setPackage("com.google.android.gms");
-        unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
+        unregIntent.putExtra("app", AndroidImplementation.getBroadcastPendingIntent(this, 0, new Intent()));
         startService(unregIntent);
     }
 
     public void lockScreen() {
         unlockScreen();
diff --git a/Ports/Android/src/com/codename1/impl/android/PushNotificationService.java b/Ports/Android/src/com/codename1/impl/android/PushNotificationService.java
index 7d0a6b4b5..e9995b047 100644
--- a/Ports/Android/src/com/codename1/impl/android/PushNotificationService.java
+++ b/Ports/Android/src/com/codename1/impl/android/PushNotificationService.java
@@ -101,11 +101,12 @@ public abstract class PushNotificationService extends Service implements PushCal
         AndroidImplementation.stopPollingLoop();
     }
     
     public abstract PushCallback getPushCallbackInstance();
     public abstract Class getStubClass();
-    
+
+
     @Override
     public void push(final String value) {
         final PushCallback callback = getPushCallbackInstance();
         if(callback != null) {
             Display.getInstance().callSerially(new Runnable() {
@@ -114,11 +115,11 @@ public abstract class PushNotificationService extends Service implements PushCal
                 }
             });
         } else {
             NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
             Intent newIntent = new Intent(this, getStubClass());
-            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+            PendingIntent contentIntent = AndroidImplementation.createPendingIntent(this, 0, newIntent);
 
 
 
             Notification.Builder builder = new Notification.Builder(this)
                     .setContentIntent(contentIntent)
diff --git a/Ports/Android/src/com/codename1/location/AndroidLocationPlayServiceManager.java b/Ports/Android/src/com/codename1/location/AndroidLocationPlayServiceManager.java
index d1a2c1134..4ecf0a9d7 100644
--- a/Ports/Android/src/com/codename1/location/AndroidLocationPlayServiceManager.java
+++ b/Ports/Android/src/com/codename1/location/AndroidLocationPlayServiceManager.java
@@ -187,13 +187,12 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
                             //intent.putExtra("backgroundClass", getBackgroundLocationListener().getName());
                             //an ugly workaround to the putExtra bug 
                             if (bgListenerClass != null) {
                                 intent.setData(Uri.parse("http://codenameone.com/a?" + bgListenerClass.getName()));
                             }
-                            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                                    intent,
-                                    PendingIntent.FLAG_UPDATE_CURRENT);
+                            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                                    intent);
                             inMemoryBackgroundLocationListener = AndroidLocationPlayServiceManager.this;
 
 
                             //LocationServices.FusedLocationApi.requestLocationUpdates(getmGoogleApiClient(), r, pendingIntent);
                             requestLocationUpdates(context, r, pendingIntent);
@@ -226,20 +225,19 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
         }
         if (!forceService && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             Intent intent = new Intent(context, BackgroundLocationBroadcastReceiver.class);
             intent.setData(Uri.parse("http://codenameone.com/a?" + bgListenerClass.getName()));
             intent.setAction(BackgroundLocationBroadcastReceiver.ACTION_PROCESS_UPDATES);
-            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = AndroidImplementation.getBroadcastPendingIntent(context, 0, intent);
             return pendingIntent;
         } else {
 
 
             Intent intent = new Intent(context, BackgroundLocationHandler.class);
             intent.setData(Uri.parse("http://codenameone.com/a?" + bgListenerClass.getName()));
-            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                    intent);
             return pendingIntent;
         }
     }
 
     static android.location.Location extractLocationFromIntent(Intent intent) {
@@ -288,13 +286,12 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
                             Context context = AndroidNativeUtil.getContext();
                             Intent intent = new Intent(context, BackgroundLocationHandler.class);
                             if (bgListenerClass != null) {
                                 intent.putExtra("backgroundClass", bgListenerClass.getName());
                             }
-                            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                                    intent,
-                                    PendingIntent.FLAG_UPDATE_CURRENT);
+                            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                                    intent);
 
                             //LocationServices.FusedLocationApi.removeLocationUpdates(getmGoogleApiClient(), pendingIntent);
                             removeLocationUpdates(context, pendingIntent);
                             inMemoryBackgroundLocationListener = null;
                         } else {
@@ -479,20 +476,19 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
             }
             Intent intent = new Intent(context, BackgroundLocationBroadcastReceiver.class);
             intent.setAction(BackgroundLocationBroadcastReceiver.ACTION_PROCESS_GEOFENCE_TRANSITIONS);
             intent.setData(Uri.parse("http://codenameone.com/a?" + geofenceListenerClass.getName()));
             //intent.setAction(BackgroundLocationBroadcastReceiver.ACTION_PROCESS_GEOFENCE_TRANSITIONS);
-            geofencePendingIntent = PendingIntent.getBroadcast(AndroidNativeUtil.getContext().getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+            geofencePendingIntent = AndroidImplementation.getBroadcastPendingIntent(AndroidNativeUtil.getContext().getApplicationContext(), 0, intent);
             return geofencePendingIntent;
         } else {
 
             Intent intent = new Intent(context, GeofenceHandler.class);
             intent.putExtra("geofenceClass", geofenceListenerClass.getName());
             intent.putExtra("geofenceID", gf.getId());
-            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                    intent);
 
 
             return pendingIntent;
         }
     }
diff --git a/Ports/Android/src/com/codename1/media/BackgroundAudioService.java b/Ports/Android/src/com/codename1/media/BackgroundAudioService.java
index 5e62bdf9a..c97d71152 100644
--- a/Ports/Android/src/com/codename1/media/BackgroundAudioService.java
+++ b/Ports/Android/src/com/codename1/media/BackgroundAudioService.java
@@ -51,10 +51,11 @@ import android.support.v4.media.session.MediaButtonReceiver;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.PlaybackStateCompat;
 
 import android.text.TextUtils;
 
+import com.codename1.impl.android.AndroidImplementation;
 import com.codename1.ui.Display;
 
 
 import java.util.List;
 
@@ -265,23 +266,20 @@ public class BackgroundAudioService extends MediaBrowserServiceCompat implements
 
         NotificationManagerCompat.from(this).notify(1, notification);
     }
 
 
-
-
-
     private void initMediaSession() {
         ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
         mMediaSessionCompat = new MediaSessionCompat(getApplicationContext(), "Tag", mediaButtonReceiver, null);
 
         mMediaSessionCompat.setCallback(mMediaSessionCallback);
         mMediaSessionCompat.setFlags( MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS | MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS );
 
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         mediaButtonIntent.setClass(this, MediaButtonReceiver.class);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
+        PendingIntent pendingIntent = AndroidImplementation.getBroadcastPendingIntent(this, 0, mediaButtonIntent);
         mMediaSessionCompat.setMediaButtonReceiver(pendingIntent);
 
         setSessionToken(mMediaSessionCompat.getSessionToken());
     }
 

Vulnerable code:     
            PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode++, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        PendingIntent contentIntent = PendingIntent.getActivity(getContext(), 0, notificationIntent, 0);
            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
        PendingIntent pendingContentIntent = PendingIntent.getActivity(getContext(), 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // boilerplate
        unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
    
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
                            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                                    intent,
                                    PendingIntent.FLAG_UPDATE_CURRENT);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
                            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                                    intent,
                                    PendingIntent.FLAG_UPDATE_CURRENT);
            geofencePendingIntent = PendingIntent.getBroadcast(AndroidNativeUtil.getContext().getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);



        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
Fixed code: 
    public static PendingIntent createPendingIntent(Context ctx, int value, Intent intent) {
        if (android.os.Build.VERSION.SDK_INT >= 23) {
            // PendingIntent.FLAG_IMMUTABLE
            return PendingIntent.getActivity(ctx, value, newIntent, 67108864);
        } else {
            return PendingIntent.getActivity(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        }
    }

    public static PendingIntent getPendingIntent(Context ctx, int value, Intent intent) {
        if (android.os.Build.VERSION.SDK_INT >= 23) {
            // PendingIntent.FLAG_IMMUTABLE
            return PendingIntent.getService(ctx, value, newIntent, 67108864);
        } else {
            return PendingIntent.getService(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        }
        PendingIntent.getService
    }

    public static PendingIntent getBroadcastPendingIntent(Context ctx, int value, Intent intent) {
        if (android.os.Build.VERSION.SDK_INT >= 23) {
            // PendingIntent.FLAG_IMMUTABLE
            return PendingIntent.getBroadcast(ctx, value, newIntent, 67108864);
        } else {
            return PendingIntent.getBroadcast(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        }
        PendingIntent.getService
    }

            PendingIntent contentIntent = createPendingIntent(context, requestCode++, newIntent);
        PendingIntent contentIntent = createPendingIntent(getContext(), 0, notificationIntent);
            PendingIntent pendingIntent = getPendingIntent(context, 0,
                    intent);
        PendingIntent pendingContentIntent = createPendingIntent(getContext(), 0, contentIntent);
        PendingIntent pendingIntent = getBroadcastPendingIntent(getContext(), 0, notificationIntent);
        PendingIntent pendingIntent = getBroadcastPendingIntent(getContext(), 0, notificationIntent);
        registrationIntent.putExtra("app", AndroidImplementation.getBroadcastPendingIntent(this, 0, new Intent())); // boilerplate
        unregIntent.putExtra("app", AndroidImplementation.getBroadcastPendingIntent(this, 0, new Intent()));


            PendingIntent contentIntent = AndroidImplementation.createPendingIntent(this, 0, newIntent);
                            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
                                    intent);
            PendingIntent pendingIntent = AndroidImplementation.getBroadcastPendingIntent(context, 0, intent);
            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
                    intent);
                            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
                                    intent);
            geofencePendingIntent = AndroidImplementation.getBroadcastPendingIntent(AndroidNativeUtil.getContext().getApplicationContext(), 0, intent);
            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
                    intent);
import com.codename1.impl.android.AndroidImplementation;
        PendingIntent pendingIntent = AndroidImplementation.getBroadcastPendingIntent(this, 0, mediaButtonIntent);