CVE-2023-42439 - Full Read SSRF in GeoNode—Simple Bypass of Whitelist Control

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