GitHub Security Advisory: GHSA-7723-35v7-qcxw
Package: activitypub_federation (RUST)
Severity: MODERATE (CVSS 4.0)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 0.6.2
Patched in: unpatched

Summary: Server-Side Request Forgery (SSRF) in activitypub_federation

Details:
### Summary
This vulnerability allows a user to bypass any predefined hardcoded URL path or security anti-Localhost mechanism and perform an arbitrary GET request to any Host, Port and URL using a Webfinger Request.

### Details
The Webfinger endpoint takes a remote domain for checking accounts as a feature, however, as per the ActivityPub spec (https://www.w3.org/TR/activitypub/#security-considerations), on the security considerations section at B.3, access to Localhost services should be prevented while running in production.
The library attempts to prevent Localhost access using the following mechanism (/src/config.rs):
```rust
pub(crate) async fn verify_url_valid(&self, url: &Url) -> Result<(), Error> {
        match url.scheme() {
            "https" => {}
            "http" => {
                if !self.allow_http_urls {
                    return Err(Error::UrlVerificationError(
                        "Http urls are only allowed in debug mode",
                    ));
                }
            }
            _ => return Err(Error::UrlVerificationError("Invalid url scheme")),
        };

        // Urls which use our local domain are not a security risk, no further verification needed
        if self.is_local_url(url) {
            return Ok(());
        }

        if url.domain().is_none() {
            return Err(Error::UrlVerificationError("Url must have a domain"));
        }

        if url.domain() == Some("localhost") && !self.debug {
            return Err(Error::UrlVerificationError(
                "Localhost is only allowed in debug mode",
            ));
        }

        self.url_verifier.verify(url).await?;

        Ok(())
    }
```
There are multiple issues with the current anti-Localhost implementation: 

1. It does not resolve the domain address supplied by the user.
2. The Localhost check is using only a simple comparison method while ignoring more complex malicious tampering attempts.
3. It filters only localhost domains, without any regard for alternative local IP domains or other sensitive domains, such internal network or cloud metadata domains.

We can reach the verify_url_valid function while sending a Webfinger request to lookup a user’s account (/src/fetch/webfinger.rs):

```rust
pub async fn webfinger_resolve_actor<T: Clone, Kind>(
    identifier: &str,
    data: &Data<T>,
) -> Result<Kind, <Kind as Object>::Error>
where
    Kind: Object + Actor + Send + 'static + Object<DataType = T>,
    for<'de2> <Kind as Object>::Kind: serde::Deserialize<'de2>,
    <Kind as Object>::Error: From<crate::error::Error> + Send + Sync + Display,
{
    let (_, domain) = identifier
        .splitn(2, '@')
        .collect_tuple()
        .ok_or(WebFingerError::WrongFormat.into_crate_error())?;
    let protocol = if data.config.debug { "http" } else { "https" };
    let fetch_url =
        format!("{protocol}://{domain}/.well-known/webfinger?resource=acct:{identifier}");
    debug!("Fetching webfinger url: {}", &fetch_url);

    l