OWASP category: MASVS-CODE: Code Quality
Overview
Android offers a powerful framework referred to as the clipboard for copying and pasting data between applications. An improper implementation of this feature could expose user-related data to unauthorized malicious actors or applications.
The specific risk associated with the exposure of clipboard data depends on the nature of the application and the Personal Identifiable Information (PII) it is handling. The impact is especially high for financial applications, as they may expose payment data, or apps that handle two-factor-authentication (2FA) codes.
The attack vectors that could be leveraged in order to exfiltrate clipboard data vary depending on Android version:
- Android versions older than Android 10 (API level 29) allow background applications to access foreground app clipboard information, potentially allowing direct access to any copied data by malicious actors.
- From Android 12 onwards (API level 31), every time an application accesses
data within the clipboard and pastes it, a toast message is shown to the user,
making it more difficult for attacks to go unnoticed. Additionally, in order to
protect PII, Android supports the
ClipDescription.EXTRA_IS_SENSITIVE
orandroid.content.extra.IS_SENSITIVE
special flag. This allows developers to visually obfuscate the clipboard content preview within the keyboard GUI, preventing copied data from being visually shown in clear-text and potentially stolen by malicious applications. Not implementing one of the aforementioned flags could in fact allow attackers to exfiltrate sensitive data copied to the clipboard by either shoulder surfing or through malicious applications that, while running in background, take screenshots or record videos of a legitimate user's activities.
Impact
The exploitation of improper clipboard handling could result in user-related sensitive or financial data being exfiltrated by malicious actors. This may aid attackers in conducting further actions such as phishing campaigns or identity theft.
Mitigations
Flag Sensitive Data
This solution is employed to visually obfuscate the clipboard content preview
within the keyboard GUI. Any sensitive data that can be copied, such as
passwords or credit card data, should be flagged with
ClipDescription.EXTRA_IS_SENSITIVE
or android.content.extra.IS_SENSITIVE
before calling ClipboardManager.setPrimaryClip()
.
Kotlin
// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
}
}
// If your app is compiled with API level 32 SDK or lower.
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean("android.content.extra.IS_SENSITIVE", true)
}
}
Java
// If your app is compiled with the API level 33 SDK or higher.
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
clipData.getDescription().setExtras(extras);
// If your app is compiled with API level 32 SDK or lower.
PersistableBundle extras = new PersistableBundle();
extras.putBoolean("android.content.extra.IS_SENSITIVE", true);
clipData.getDescription().setExtras(extras);
Enforce Latest Android Versions
Enforcing the app to run on Android versions later or equal to Android 10 (API 29) prevents background processes from accessing clipboard data in the foreground application.
To enforce the app to run only on Android 10 (API 29) or later, set the following values for the version settings in the Gradle build files within your project in Android Studio.
Groovy
android {
namespace 'com.example.testapp'
compileSdk [SDK_LATEST_VERSION]
defaultConfig {
applicationId "com.example.testapp"
minSdk 29
targetSdk [SDK_LATEST_VERSION]
versionCode 1
versionName "1.0"
...
}
...
}
...
Kotlin
android {
namespace = "com.example.testapp"
compileSdk = [SDK_LATEST_VERSION]
defaultConfig {
applicationId = "com.example.testapp"
minSdk = 29
targetSdk = [SDK_LATEST_VERSION]
versionCode = 1
versionName = "1.0"
...
}
...
}
...
Delete Clipboard content after a defined period of time
If the application is meant to run on Android versions lower than Android 10 (API level 29), any background application can access clipboard data. In order to reduce this risk, it's useful to implement a function that clears any data copied to the clipboard after a specific period of time. This function is automatically performed starting with Android 13 (API level 33). For older Android versions, this deletion can be performed by including the following snippet within the application's code.
Kotlin
//The Executor makes this task Asynchronous so that the UI continues being responsive
backgroundExecutor.schedule({
//Creates a clip object with the content of the Clipboard
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = clipboard.primaryClip
//If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clipboard.clearPrimaryClip()
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
//If SDK version is lower than 28, it will replace Clipboard content with an empty value
val newEmptyClip = ClipData.newPlainText("EmptyClipContent", "")
clipboard.setPrimaryClip(newEmptyClip)
}
//The delay after which the Clipboard is cleared, measured in seconds
}, 5, TimeUnit.SECONDS)
Java
//The Executor makes this task Asynchronous so that the UI continues being responsive
ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
backgroundExecutor.schedule(new Runnable() {
@Override
public void run() {
//Creates a clip object with the content of the Clipboard
ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
//If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clipboard.clearPrimaryClip();
//If SDK version is lower than 28, it will replace Clipboard content with an empty value
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
ClipData newEmptyClip = ClipData.newPlainText("EmptyClipContent", "");
clipboard.setPrimaryClip(newEmptyClip);
}
//The delay after which the Clipboard is cleared, measured in seconds
}, 5, TimeUnit.SECONDS);
Resources
- The clipboard framework
- System notification shown when your app accesses clipboard data
- Add sensitive content to the clipboard
- Privacy changes in Android 10
- Set app version information