Port MASTG v1->v2 MASTG-TEST-0002: Testing Local Storage for Input Validation (android) (by @appknox)#3328
Port MASTG v1->v2 MASTG-TEST-0002: Testing Local Storage for Input Validation (android) (by @appknox)#3328jeel38 wants to merge 23 commits intoOWASP:masterfrom
Conversation
Co-authored-by: pruDhv! <58649792+sk3l10x1ng@users.noreply.github.com>
|
@cpholguera, upon adding the depreciation note, getting branch gets a conflict |
|
Maybe the branch was a bit old. We added "profiles" now for all tests. I fixed the conflict for you Please add |
|
The new profiles (previously known as "levels") are defined here: https://docs.google.com/document/d/1paz7dxKXHzAC9MN7Mnln1JiZwBNyg7Gs364AJ6KudEs/edit?usp=sharing |
Done |
|
@cpholguera please review it |
|
Please fix the issues reported by Copilot in section "Comments suppressed due to low confidence (5)" Also, I agree with Copilot's comment about:
If you're conducting a pentest, would you report this as an issue? "The app uses |
|
There's another problem that will probably be solved when you fix the copilot issues. Are you able to read these logs? https://github.com/OWASP/owasp-mastg/actions/runs/15554645412/job/43792346017?pr=3328
|
|
@cpholguera please check |
There was a problem hiding this comment.
Pull Request Overview
This PR ports MASTG-TEST-0002 from version 1 to version 2, creating a new test for detecting use of local storage for input validation in Android applications. The focus shifts from general local storage testing to specifically checking for integrity validation when reading from SharedPreferences.
- Deprecates the old MASTG-TEST-0002 and creates MASTG-TEST-0288 as the new version
- Implements static analysis detection for SharedPreferences usage without integrity checks
- Provides demonstration code showing both vulnerable and secure patterns using HMAC validation
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/android/MASVS-CODE/MASTG-TEST-0002.md | Marks the original test as deprecated with reference to new version |
| tests-beta/android/MASVS-CODE/MASTG-TEST-0288.md | New test specification for detecting SharedPreferences without integrity validation |
| rules/mastg-android-local-storage-input-validation.yml | Semgrep rule to detect insecure SharedPreferences usage patterns |
| demos/android/MASVS-CODE/MASTG-DEMO-0061/ | Complete demonstration including vulnerable Java code, secure Kotlin implementation, and analysis output |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| - L2 | ||
| profiles: [L1, L2] | ||
| status: deprecated | ||
| covered_by: [MASTG-TEST-0281] |
There was a problem hiding this comment.
The deprecation references MASTG-TEST-0281, but the actual replacement test created in this PR is MASTG-TEST-0288. This should be corrected to reference the correct test ID.
| covered_by: [MASTG-TEST-0281] | |
| covered_by: [MASTG-TEST-0288] |
|
|
||
| ## Steps | ||
|
|
||
| 1. Run a static analysis tool such as @MASTG-TOOL-0110 on the code and look for uses of the `putString` and `getString`. |
There was a problem hiding this comment.
There was a problem hiding this comment.
This is an old file
|
@cpholguera requested changes be made. Could you please check |
|
@cpholguera can you please review |
|
@cpholguera can you please review it |
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| --- | ||
| title: Use of Local Storage for Input Validation | ||
| platform: android | ||
| id: MASTG-TEST-0288 |
There was a problem hiding this comment.
you might need a new id just before merge (test 288 already exists)
| @@ -0,0 +1,24 @@ | |||
| --- | |||
| title: Use of Local Storage for Input Validation | |||
There was a problem hiding this comment.
How about the following? Input validation to me sounds validating input rather than checking the integrity/authenticity of data.
| title: Use of Local Storage for Input Validation | |
| title: Validation of Local Storage Data |
or
| title: Use of Local Storage for Input Validation | |
| title: Integrity and Authenticity Validation of Local Storage Data |
| SecureSharedPreferences insecurePrefs = new SecureSharedPreferences(this.context, false); | ||
| insecurePrefs.saveData("user_role_insecure", "user"); | ||
| SecureSharedPreferences securePrefs = new SecureSharedPreferences(this.context, true); | ||
| securePrefs.saveData("user_role_secure", "user"); |
There was a problem hiding this comment.
Extracting this file gives quite a different result. Most importantly, the following. Therefore, Semgrep finds no results for me.
| SecureSharedPreferences insecurePrefs = new SecureSharedPreferences(this.context, false); | |
| insecurePrefs.saveData("user_role_insecure", "user"); | |
| SecureSharedPreferences securePrefs = new SecureSharedPreferences(this.context, true); | |
| securePrefs.saveData("user_role_secure", "user"); | |
| saveData("user_role_insecure", "user", false); | |
| saveData("user_role_secure", "user", true); |
There was a problem hiding this comment.
Can you share your output.txt as showing the result of finding
There was a problem hiding this comment.
Is this file LLM generated or did you actually pull it from the device? Please use the MastgTest.kt as input on the demo app.
The output.txt of the actual MastgTest.kt which is very different than this file is empty.
There was a problem hiding this comment.
This is not a LLM Generated, it's a Reversed while MastgTest_reversed.java from MastgTest.kt file
| return "INITIAL SETUP COMPLETE.\n\n" + | ||
| "The role for both secure and insecure tests has been set to 'user'.\n\n" + | ||
| "ACTION REQUIRED:\n" + | ||
| "1. Use a file explorer or ADB shell on a rooted device.\n" + | ||
| "2. Go to: /data/data/org.owasp.mastestapp/shared_prefs/\n" + | ||
| "3. Open the file: app_settings.xml\n" + | ||
| "4. Change BOTH <string>user</string> values to <string>admin</string>.\n" + | ||
| "5. Save the file and run this test again to see the results." |
There was a problem hiding this comment.
Well done on he pen-testing example! 👏 I followed the steps but sadly could not "tamper" it.
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="user_role_secure_hmac">690d026aeeba673e7225ee95a3460a0054752777afec8e4fb7ec8294934011ed</string>
<boolean name="setup_complete" value="true" />
<string name="user_role_insecure">admin</string>
<string name="user_role_secure">admin</string>
</map> is the file state between the 2 steps
There was a problem hiding this comment.
You have to edit "user_role_insecure" value and restart the application
There was a problem hiding this comment.
This is tested on physical rooted Android device. Please refer to the attached POC video
Screen.Recording.2026-01-30.at.12.mp4
| results.append(">> OUTCOME: NOT TAMPERED. The role is still '$secureRole', and its HMAC signature is valid.\n") | ||
| } | ||
|
|
||
| results.append("\n\nTest complete. To run the setup again, please clear the application's data in Android Settings and restart the test.") |
There was a problem hiding this comment.
fyi restarting the application (thus test) would rewrite the xml. No need for clearing app data
There was a problem hiding this comment.
To get tamper data, you have to restart the application, clearing app data is reset to application default settings.
There was a problem hiding this comment.
The message/user direction is wrong.
- If I restart the application it will override the shared prefs to default -> "user"
- Thus clearing the data is not required.
In combination with the fact that I could not "tamper" the app as explained in the other comment, please carefully re-check the demo and its instructions.
|
@Diolor please review, changes are completed |
|
@Diolor please review |
| - L2 | ||
| profiles: [L1, L2] | ||
| status: deprecated | ||
| covered_by: [MASTG-TEST-0288] |
There was a problem hiding this comment.
indicating that this might change
There was a problem hiding this comment.
This is been addressed
| For any publicly accessible data storage, any process can override the data. This means that input validation needs to be applied the moment the data is read back again. | ||
|
|
||
| > Note: The same is true for private accessible data on a rooted device |
There was a problem hiding this comment.
This v1 test addresses 2 issues:
- Publicly accessible data
- Private accessible data on a rooted device
As stated in the comment on the Tests' overview, the second case is not addressed on the v2 test.
There was a problem hiding this comment.
Here, the demo covers "Private accessible data on a rooted device" as per the static analysis of the previous V1 test. Private test data path: /data/data/org.owasp.mastestapp/shared_prefs
|
|
||
| ## Evaluation | ||
|
|
||
| The test fails if the application does not verify the integrity and authenticity of data loaded from local storage such as `SharedPreferences`. |
There was a problem hiding this comment.
Does that mean we should verify integrity + authenticity for all data in SharedPrefs? E.g. a true/false boolean if the app should render light or dark them is not important.
Without adding the context of sensitive data or data that could harm the apps, this wording is very generalised.
| package org.owasp.mastestapp | ||
|
|
||
| import android.content.Context | ||
| import android.content.SharedPreferences |
There was a problem hiding this comment.
This is been addressed
| return "INITIAL SETUP COMPLETE.\n\n" + | ||
| "The role for both secure and insecure tests has been set to 'user'.\n\n" + | ||
| "ACTION REQUIRED:\n" + | ||
| "1. Use a file explorer or ADB shell on a rooted device.\n" + | ||
| "2. Go to: /data/data/org.owasp.mastestapp/shared_prefs/\n" + | ||
| "3. Open the file: app_settings.xml\n" + | ||
| "4. Change BOTH <string>user</string> values to <string>admin</string>.\n" + | ||
| "5. Save the file and run this test again to see the results." |
| results.append(">> OUTCOME: NOT TAMPERED. The role is still '$secureRole', and its HMAC signature is valid.\n") | ||
| } | ||
|
|
||
| results.append("\n\nTest complete. To run the setup again, please clear the application's data in Android Settings and restart the test.") |
There was a problem hiding this comment.
The message/user direction is wrong.
- If I restart the application it will override the shared prefs to default -> "user"
- Thus clearing the data is not required.
In combination with the fact that I could not "tamper" the app as explained in the other comment, please carefully re-check the demo and its instructions.
| SecureSharedPreferences insecurePrefs = new SecureSharedPreferences(this.context, false); | ||
| insecurePrefs.saveData("user_role_insecure", "user"); | ||
| SecureSharedPreferences securePrefs = new SecureSharedPreferences(this.context, true); | ||
| securePrefs.saveData("user_role_secure", "user"); |
There was a problem hiding this comment.
Is this file LLM generated or did you actually pull it from the device? Please use the MastgTest.kt as input on the demo app.
The output.txt of the actual MastgTest.kt which is very different than this file is empty.
| 23┆ SecureSharedPreferences insecurePrefs = new | ||
| SecureSharedPreferences(this.context, false); |
There was a problem hiding this comment.
Note: You might have hard wrapping in your editor.
There was a problem hiding this comment.
This is been addressed
|
@Diolor please review it |


Closes #2995
This PR ports MASTG-TEST-0002 from version 1 to version 2, creating a new test for detecting use of local storage for input validation in Android applications. The focus shifts from general local storage testing to specifically checking for integrity validation when reading from
SharedPreferences.SharedPreferencesusage without integrity checksSharedPreferenceswithout integrity validationSharedPreferencesusage patterns