GeoNode is an open source platform that lets organizations create, publish, and share geospatial data and maps. It’s widely used in both public and private agencies for sharing maps and spatial datasets. However, in versions starting from 3.2. up to 4.1.3, a critical security vulnerability was discovered: CVE-2023-42439, a Server-Side Request Forgery (SSRF) bug that lets attackers read arbitrary data from services inside your private network—even when a whitelist is enabled.
Below, I’ll explain the vulnerability, show you the code that’s affected, walk through a working exploit, and share how to patch it. All in clear—and exclusive—language!
Exploit: Simple whitelist bypass using @ or %40 in URL
- Patch available? Yes (GeoNode 4.1.3.post1)
What is SSRF, and Why Does it Matter?
SSRF is when you trick a web server into fetching any URL you want. The server often has more access than you, so if it can hit localhost or other internal resources, you may see sensitive data.
Developers defend against SSRF by restricting outgoing requests to “safe” addresses (the whitelist). But this bug in GeoNode lets attackers dodge those rules with a simple URL trick.
The Vulnerability: How the Whitelist Fails
GeoNode includes a function to fetch data from URLs, with a “host whitelist” to prevent abusing this feature. Here’s an abstract of the vulnerable logic (simplified):
from urllib.parse import urlparse
def fetch_url(url):
whitelisted = ["example.com", "data.geonode.org", "10...1"]
parsed = urlparse(url)
host = parsed.hostname
if host not in whitelisted:
raise Exception("Host not allowed!")
# Actual dangerous request
resp = requests.get(url)
return resp.text
Looks solid, right? GeoNode checks the host, and only allows certain domains/IPs. But URLs are tricky—URL parsers don’t always behave like browsers or requests.
The trick is to add either @ (or its URL encoding %40) in the host field. Here’s how
- The URL standard lets you use user@host: http://user@host:port/path
- Most URL parsers (including Python’s) treat everything before @ as credentials. The part after @ is the hostname.
Example
http://example.com@localhost:808/admin
urlparse() sees: host = example.com (whitelisted! Allowed!)
- But the browser or requests library treats it as credentials for localhost:808 and tries to access *localhost*.
If you replace @ with %40, you get the same effect
http://example.com%40localhost:808/admin
Live Exploit Example
Suppose you want to fetch data from a private GeoServer on the same network (localhost:808), but only example.com is whitelisted.
Step 1: Craft the exploit URL
http://example.com@127...1:808/rest?format=json
OR
http://example.com%40127...1:808/rest?format=json
Server logic: “127...1 not whitelisted? Nope. example.com? Yep! Go ahead.”
- Actual fetch: Hits 127...1:808/rest, often exposing secret data.
Step 2: Abuse the Endpoint
You’d send this URL to the vulnerable feature, for instance—say, through an import interface or a “Get Layer Preview” function.
Step 3: Enjoy Full Read SSRF
The server fetches the data from localhost or your chosen internal IP and returns all the response data.
Read internal files or application endpoints not exposed to the internet
- Fetch sensitive configuration, API keys, or running container metadata (e.g., AWS Instance Metadata)
Fingerprint internal services and subnets
This turns many simple GeoNode deployments into a pivot point to attack your whole infrastructure.
How Was It Fixed?
A simple version check is NOT enough. Here’s what GeoNode did: (Relevant Commit)
After properly parsing the URL, they re-check the *last* real hostname after any @
- They reject any URL where the address (after @) is not on the whitelist—even if the credentials are whitelisted
Fixed code (simplified)
parsed = urlparse(url)
# Use 'parsed.hostname', which is the host AFTER any '@' userinfo
host = parsed.hostname
if host not in whitelisted:
raise Exception("Host not allowed!")
Key: Always validate what the final request will *actually* target, not just what the string looks like.
Recommendations
- Update immediately: At least to GeoNode 4.1.3.post1
- Review your own SSRF protections: Never parse hosts using string functions; always use a safe URL parser, and apply whitelists to the *effective* hostname.
- Audit for internal exposure: Anything that calls out to URLs from user-supplied input should be checked.
References
- GeoNode Security Advisory, GHSA-7x54-q4v5-c68j
- CVE-2023-42439 at CVE.org
- GeoNode Release 4.1.3.post1
- Original fix commit
Conclusion
CVE-2023-42439 is a textbook case of why SSRF is dangerous and why input validation must match actual backend behavior. If you use GeoNode, update now. If you build anything that fetches URLs from users, double-check your own defenses.
Timeline
Published on: 09/15/2023 21:15:11 UTC
Last modified on: 11/04/2023 02:00:21 UTC