Skip to content
Open
32 changes: 29 additions & 3 deletions demos/android/MASVS-STORAGE/MASTG-DEMO-0068/MASTG-DEMO-0068.md

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The DEMO must follow the content guidelines (https://mas.owasp.org/contributing/writing-content/mastg-demo.instructions).

For example, the "Evaluation" section should explain each relevant line of the output that is used as an evidence to give a FAIL to the test.

Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
---
platform: android
title: Reserved for MASWE-0006 - Unencrypted SQLite Storage (Alternative Demo)
title: Sensitive Data in Unencrypted SQLite
id: MASTG-DEMO-0068
code: [kotlin]
test: MASTG-TEST-0304
Comment thread
macik09 marked this conversation as resolved.
status: placeholder
note: This placeholder reserves the ID for a potential alternative or expanded demo related to unencrypted SQLite storage, linked to the MASTG-TEST-0304 test case.
status: new
---

### Sample

The snippet below shows sample code that uses the default SQLite API (`context.openOrCreateDatabase`) to store sensitive data, including PII and an access token, without any encryption.

{{ MastgTest.kt }}

### Steps

1. Install the app on a device (@MASTG-TECH-0005)
2. Make sure you have @MASTG-TOOL-0004 installed on your machine
3. Click the **Start** button
4. Execute `run.sh`.

The script `run.sh` pulls the database file (`PrivateUnencryptedData.db`) and queries its content:

{{ run.sh }}

### Observation

The output contains the extracted content from the `Users` table, showing the sensitive PII (email address) and the access token stored in **plaintext**.

{{ output.txt }}

### Evaluation

This test fails because the app uses the standard SQLite API to store sensitive data, specifically an access token (secret) and the user's email address (PII), in its sandbox without additional encryption.
42 changes: 42 additions & 0 deletions demos/android/MASVS-STORAGE/MASTG-DEMO-0068/MastgTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.owasp.mastestapp

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.util.Log

class MastgTest (private val context: Context){


fun writeSensitiveDataToUnencryptedSQLite() {
val username = "demoUser_sqlite"
val userEmail = "john.doe@maswe-0006.com"
val accessToken = "ghp_1234567890abcdefghijklmnopqrstuvABCD"
val dbName = "PrivateUnencryptedData"

try {
val db: SQLiteDatabase = context.openOrCreateDatabase(
dbName,
Context.MODE_PRIVATE,
null
)

db.execSQL("CREATE TABLE IF NOT EXISTS Users(Username VARCHAR, Email VARCHAR, Token VARCHAR);")


db.execSQL("DELETE FROM Users;")

db.execSQL("INSERT INTO Users VALUES('$username', '$userEmail', '$accessToken');")

db.close()
Log.i("MASTG-SQLITE", "Data written to unencrypted database: $dbName. Ready for ADB extraction.")

} catch (e: Exception) {
Log.e("MASTG-SQLITE", "Error writing data to SQLite: ${e.message}")
}
}

fun mastgTest(): String {
writeSensitiveDataToUnencryptedSQLite()
return "SQLite Demo Complete. Database 'PrivateUnencryptedData' created with PII and Token."
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This Java file does not seem to be the Java file resulting from decompiling the DEMO app. As commented previously, follow the DEMO guidelines (https://mas.owasp.org/contributing/writing-content/mastg-demo.instructions/) to provide these files accordingly.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.owasp.mastestapp;

import android.content.Context;
import android.util.Log;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;

/* compiled from: MastgTest.kt */
@Metadata(d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\u000f\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0004\b\u0004\u0010\u0005J\u0006\u0010\u0006\u001a\u00020\u0007R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\b"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "<init>", "(Landroid/content/Context;)V", "mastgTest", "", "app_debug"}, k = 1, mv = {2, 0, 0}, xi = 48)
/* loaded from: classes3.dex */
public final class MastgTest {
public static final int $stable = 8;
private final Context context;

public MastgTest(Context context) {
Intrinsics.checkNotNullParameter(context, "context");
this.context = context;
}

public final String mastgTest() throws Exception {
DemoResults r = new DemoResults("0000");
try {
Log.d("MASTG-TEST", "Hello from the OWASP MASTG Test app.");
r.add(Status.PASS, "The app implemented a demo which passed the test with the following value: 'Hello from the OWASP MASTG Test app.'");
r.add(Status.FAIL, "The app implemented a demo which failed the test.");
throw new Exception("Example exception: Method not implemented.");
} catch (Exception e) {
r.add(Status.ERROR, e.toString());
return r.toJson();
}
}
}
2 changes: 2 additions & 0 deletions demos/android/MASVS-STORAGE/MASTG-DEMO-0068/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--- Users Table Content ---
demoUser_sqlite|john.doe@maswe-0006.com|MASTG_ACCESS_TOKEN_B4C8D2F0E7A
23 changes: 23 additions & 0 deletions demos/android/MASVS-STORAGE/MASTG-DEMO-0068/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
Comment thread
macik09 marked this conversation as resolved.

PACKAGE="org.owasp.mastestapp"
DB_NAME="PrivateUnencryptedData"
DB_PATH="/data/data/$PACKAGE/databases/$DB_NAME"
SDCARD_PULL_PATH="/sdcard/$DB_NAME.db"
OUTPUT_DB_FILE="${DB_NAME}.db"
OUTPUT_TXT_FILE="output.txt"

# Copy Database to the sdcard
if ! adb shell "run-as $PACKAGE cp databases/$DB_NAME $SDCARD_PULL_PATH"; then
echo "run-as failed, trying su"
adb shell "su 0 sh -c 'cp $DB_PATH $SDCARD_PULL_PATH'"
fi

# Pull the file to the host machine
adb pull "$SDCARD_PULL_PATH" .

echo "--- Users Table Content ---" > $OUTPUT_TXT_FILE
sqlite3 "$OUTPUT_DB_FILE" "SELECT * FROM Users;" >> $OUTPUT_TXT_FILE

adb shell "rm $SDCARD_PULL_PATH" 2>/dev/null
rm $OUTPUT_DB_FILE 2>/dev/null
Comment thread
macik09 marked this conversation as resolved.
63 changes: 59 additions & 4 deletions tests-beta/android/MASVS-STORAGE/MASTG-TEST-0304.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,66 @@
---
title: Sensitive Data Stored Unencrypted via SQLite
platform: android
title: Sensitive Data Stored Unencrypted via SQLite
id: MASTG-TEST-0304
type: [static, dynamic]
weakness: MASWE-0006
best-practices: []
best-practices: [MASTG-BEST-0074]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please add a new MASTG-BEST file for this. I think you just need one for all these PRs where you cover the best practices for MASWE-0006 on Android

  • Title could be "Encrypt Sensitive Data in Private Storage Locations"
  • Sections could include (please elaborate, see other best practice files):
    • Avoid storing sensitive data locally if not required for application functionality to reduce the likelihood and impact of this weakness.

    • Use platform-provided features for encrypting data at rest. For example, on Android, use EncryptedFile or EncryptedSharedPreferences (or equivalent, note that they are actually deprecated).

    • Using envelope encryption with Data Encryption Keys (DEK) and Key Encryption Keys (KEK) or equivalent methods.

      • Examples mentioning SQLite, DataStore, etc.
    • Use libs like SQLCipher

    • etc.

profiles: [L1, L2]
status: placeholder
note: This test checks if the app uses the default SQLite API (e.g., `SQLiteOpenHelper`, `context.openOrCreateDatabase`) to store sensitive data (e.g., tokens, PII) in an unencrypted database file within the app's sandbox. It confirms the absence of secure alternatives like SQLCipher or encrypted databases.
status: new
---

## Overview

This test verifies whether an app stores sensitive data — such as tokens, credentials, or personally identifiable information (PII) — in SQLite databases without encryption.
Comment thread
macik09 marked this conversation as resolved.
Outdated
SQLite databases created using APIs like `SQLiteOpenHelper` or `context.openOrCreateDatabase` are not encrypted by default.
The goal of this test is to determine whether the app relies on plaintext SQLite storage instead of secure alternatives (e.g., SQLCipher or encrypted database frameworks).

---

## Steps

### Static Analysis

1. Obtain the application package (e.g., APK file) using @MASTG-TECH-0003.

2. Use a static analysis technique (@MASTG-TECH-0014) to review the code and identify references to SQLite APIs such as:
- `SQLiteOpenHelper`
- `context.openOrCreateDatabase`
- `SQLiteDatabase#insert`, `query`, `execSQL`, etc.

3. Review database creation and insertion logic to determine whether:
- the database is created using default (unencrypted) SQLite,
- no encryption layer or secure wrapper is applied (e.g., SQLCipher),
- sensitive fields (tokens, secrets, PII) are inserted without transformation or protection.

### Dynamic Analysis

1. Install and run the app on a rooted or emulated device (@MASTG-TECH-0005).

2. Trigger app functionality that processes or stores sensitive data.

3. Access the app's private storage and locate SQLite database files (e.g., files with `db`, `sqlite`, `sqlite3`). This requires accessing the app data directories (@MASTG-TECH-0008).

4. Extract the database file from the device to the host machine using @MASTG-TECH-0003.

5. Inspect the database content using a suitable tool, applying the technique for Dynamic Analysis (@MASTG-TECH-0015) to confirm whether sensitive data is stored in plaintext.

---

## Observation

The output should indicate:

- which SQLite databases the app creates,
- whether sensitive data (tokens, secrets, PII) is present inside these databases,
- whether the stored values appear in plaintext.

---

## Evaluation

The test fails if:

- sensitive data is stored using the default, unencrypted SQLite implementation,
- no encryption mechanism (SQLCipher or equivalent) protects the stored data,
- sensitive values inside the database can be read in plaintext through static or dynamic analysis.