Make WordPress Core

Opened 7 weeks ago

Last modified 7 weeks ago

#60934 new defect (bug)

Internal Subnets are being blocked by wp_parse_url and why?

Reported by: erenfro's profile erenfro Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: trunk
Component: HTTP API Keywords: close reporter-feedback
Focuses: Cc:

Description

https://github.com/WordPress/wordpress-develop/blob/6.5/src/wp-includes/http.php#L566-L588

This code block has plagued me for months trying to identify what the cause of WordPress, ActivityPub, Friends, and Mastodon plugins could/would not work with my Friendica or Mastodon instances, and it's been because of these lines of code literally blocking it from even trying.

I think this is a bad way to handle this, and I'm wondering why this literally non-essential software-level "firewall"-like code was put in. Malicious code certainly would not even bother to use wp_parse_url at all, let alone utilise this function to engage in things. Everyone I'd spoken to either had no clue about this as well, just assuming WordPress had nothing like this there, which is clearly inaccurate given the code right there.

Furthermore, there's literally no known documentation I could find about this, none within WordPress for sure. Through external resources I managed to find a way to get around this issue by creating a custom plugin that used a custom add_filter() to define a new instance, by each and every involved host by FQDN, to allow in this wp_http_validate_url function call.

So, why does this code block exist to block internal IP subnets? If that's ever needed, one can literally do so at their firewalls where it should be, not bolted into their web application's code and blocking by default. And especially not documented or providing any clear cut means to add rules in a reasonable manner towards this at the VERY least.

Change History (5)

#1 @dd32
7 weeks ago

  • Keywords close reporter-feedback added
  • Severity changed from blocker to normal

Hi @erenfro,

This functionality is part of wp_safe_remote_request() - to only fetch "safe" remote destinations.

This is intended to protect against SSRF attacks, in which an application is 'tricked' to request non-public resources and expose them publicly through the accessible endpoint. We additionally protect against redirection attacks used to start a SSRF attack.

Unlike suggested, this doesn't affect wp_parse_url() but rather wp_http_validate_url() - which is only intended on being used to validate that a URL can be requested "safely" by the HTTP API. A number of plugins do use this function improperly though.

It's also common for plugins to run into this by feeling that the resources they are requesting are "safe" but WordPress disagreeing, this happens due to the inability of WordPress to know what is safe about a non-public resource, plugins should use the non-safe request method for that.

In short:

  • To request potentially unsafe resources, wp_remote_request() / wp_remote_get() can be used. Local non-public resources are allowed to be requested.
  • To request only-safe resources, wp_safe_remote_request() / wp_safe_remote_get() can be used. Local non-public resources will be blocked.

If you could expand on your use-case and the issue encountered, there might be more to it, but from the description provided and the above explanation, I believe this ticket can be closed as invalid.

#2 @erenfro
7 weeks ago

Well in my case, the use-case was the use of the extensions known as ActivityPub, Friends, and Enable Mastodon Apps, and NodeInfo. At least some of which I know actively uses wp_http_validate_url() directly as part of their own checks.

#4 @dd32
7 weeks ago

Upon looking at some of those examples provided, they seem like valid uses of the functionality. Primarily as in those cases, one would not want to request an internal URL.

With the additional information from one of the tickets created on the plugins:

run on the very same cluster of servers running my WordPress site, that no traffic ever left WordPress or my webserver specifically while resolving the mastodon's domain name to a local internal subnet IP. When changing this to an external internet address IP, however, things magically worked.

I would say this is a server configuration issue; as although I understand why you'd want to resolve it locally (Probably because the external-ip isn't routable from the cluster, or, doing so does leave the network only to come back) doing so makes it impossible to differentiate the public sites from say, your security cameras web interface that's only otherwise accessible to your LAN.

In that case, the correct way is to use the http_request_host_is_external filter to specify that "Yes, mydomain.tld resolved to 10.2.3.4 but it IS an external URL and not local, proceed with requesting it".

#5 @erenfro
7 weeks ago

Okay. In think then in the case of this report, at the very least, this needs to be documented better, and possibly even reasonable examples of _how_ to work with this, because the way people are doing it ends up actually often times being worse. Or maybe even a whitelist rules editor added into WordPress to be able to configure this, rather than it being basically a black hole solution that literally nobody, but wordpress developers, and some plugin developers, even know about. I went through various WordPress communities over this issue. IRC, Discord, non-specific communities that weren't specific to wordpress but were involved in social communities and the likes, but literally nobody know about this, and to me, that's a problem. It solves a problem, sure, but without ever providing a clear understanding of it.

Note: See TracTickets for help on using tickets.