Skip to content

fix(data): prevent SSRF from untrusted KML/GeoJSON icon and GroundOverlay href - #1758

Open
herdiyana256 wants to merge 1 commit into
googlemaps:mainfrom
herdiyana256:fix/kml-geojson-icon-href-ssrf
Open

fix(data): prevent SSRF from untrusted KML/GeoJSON icon and GroundOverlay href#1758
herdiyana256 wants to merge 1 commit into
googlemaps:mainfrom
herdiyana256:fix/kml-geojson-icon-href-ssrf

Conversation

@herdiyana256

Copy link
Copy Markdown

Summary

Icon and GroundOverlay <href> URLs are read from the parsed KML/GeoJSON document and fetched without any validation, giving a crafted (untrusted) document a Server-Side Request Forgery (SSRF) primitive.

  • Style/IconStyle/Icon/hrefKmlStyle.iconUrl
  • GroundOverlay/Icon/hrefKmlGroundOverlay.imageUrl

Both flow to UrlIconProvider.loadBitmapFromUrl, which did:

val url = URL(urlString)
val connection = url.openConnection() as HttpURLConnection
connection.doInput = true
connection.connect()          // <-- request issued; no validation anywhere

A malicious KML/GeoJSON (downloaded, shared, or user-provided) can therefore make the app issue requests to loopback, link-local (169.254.169.254 metadata), and private-network hosts reachable from the device. HttpURLConnection also follows redirects by default, so a public-looking href can 302 to an internal target.

The KmlUrlSanitizer interface exists but sanitizeUrl(...) is never called anywhere in the codebase (dead code), and KmlLayer/GeoJsonLayer hard-code UrlIconProvider() with no way to inject one — so there was no protection by default and no way for a developer to add one.

Reproduction (network sequence is verbatim from loadBitmapFromUrl)

A KML with <Icon><href>http://127.0.0.1:8474/INTERNAL</href></Icon> (or a 169.254.169.254 / RFC1918 host) causes a real request to that host; a redirector href is followed to the internal target. Confirmed against a local listener that logged the inbound requests.

Fix

  • DefaultKmlUrlSanitizer (new): allows only http/https whose host does not resolve to a loopback / any-local / link-local / site-local (RFC 1918) / multicast address; returns null (block) otherwise. Public icon/overlay URLs are unaffected.
  • UrlIconProvider now applies a KmlUrlSanitizer (secure default) before every fetch — blocked URLs issue no request — and sets instanceFollowRedirects = false to stop redirect-based bypass. Callers may pass a custom sanitizer, or null to opt out.
  • Hermetic unit tests for the sanitizer (IP-literal hosts, no DNS/network).

This makes the previously-dead KmlUrlSanitizer functional and the default behavior secure, without changing the public KmlLayer/GeoJsonLayer API. Verified on a JVM: internal/metadata/RFC1918/redirector/file:// hrefs are blocked with no request issued, while a public host still loads.

Scope / notes

  • DNS-rebinding between the sanitizer's resolution and the connection's resolution is a known residual limitation of host-based validation; disabling auto-redirects and failing closed on unresolved hosts substantially reduces the attack surface.

…rlay href

Icon (IconStyle/Icon/href) and GroundOverlay (Icon/href) URLs are read from the
parsed KML/GeoJSON document, which is frequently untrusted (downloaded, shared,
or user-provided). UrlIconProvider.loadBitmapFromUrl fetched these URLs verbatim
(URL(href).openConnection().connect()) with no validation, giving a crafted
document an SSRF primitive against loopback, link-local (169.254.169.254 metadata),
and private-network hosts reachable from the device. The existing KmlUrlSanitizer
interface was never invoked anywhere (dead code) and could not be injected through
KmlLayer/GeoJsonLayer, so there was no protection by default.

- Add DefaultKmlUrlSanitizer: allows only http/https whose host does not resolve to
  a loopback/any-local/link-local/site-local/multicast address; blocks otherwise.
- UrlIconProvider now applies a KmlUrlSanitizer (secure default) before every fetch
  and disables auto-redirects to stop redirect-based SSRF bypass. Callers may pass a
  custom sanitizer, or null to opt out. Public icon URLs are unaffected.
- Add hermetic unit tests for the sanitizer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants