Every CVE Search/ Get API key

CVE-2025-25194

Server-Side Request Forgery (SSRF) in activitypub_federation

4.0 Medium

Lemmy, a link aggregator and forum for the fediverse, is vulnerable to server-side request forgery via a dependency on activitypub_federation, a framework for ActivityPub federation in Rust. This vulnerability, which is present in versions 0.6.2 and prior of activitypub_federation and versions 0.19.8 and prior of Lemmy, 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. As of time of publication, a fix has not been made available.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
Low
Integrity
None
Availability
None

Exploit likelihood

0.42%Up 0.4 points since Feb 11, 2025
90%50%10%1%

What each source reports

CVE List Score used 4.0

Server-Side Request Forgery (SSRF) in activitypub_federation

Lemmy, a link aggregator and forum for the fediverse, is vulnerable to server-side request forgery via a dependency on activitypub_federation, a framework for ActivityPub federation in Rust. This vulnerability, which is present in versions 0.6.2 and prior of activitypub_federation and versions 0.19.8 and prior of Lemmy, 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. As of time of publication, a fix has not been made available.

Record
CVE-2025-25194
CVSS 3.1
4.0 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
EUVDEUVD-2025-4082 4.0

Lemmy, a link aggregator and forum for the fediverse, is vulnerable to server-side request forgery via a dependency on activitypub_federation, a framework for ActivityPub federation in Rust. This vulnerability, which is present in versions 0.6.2 and prior of activitypub_federation and versions 0.19.8 and prior of Lemmy, 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. As of time of publication, a fix has not been made available.

Record
EUVD-2025-4082
CVSS 3.1
4.0 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N
Updated
2026-11-03
GitHub AdvisoriesGHSA-7723-35v7-qcxw 4.0

Server-Side Request Forgery (SSRF) in activitypub_federation

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):

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):

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);

    let res: Webfinger = fetch_object_http_with_accept(
        &Url::parse(&fetch_url).map_err(Error::UrlParse)?,
        data,
        &WEBFINGER_CONTENT_TYPE,
    )
    .await?
    .object;

    debug_assert_eq!(res.subject, format!("acct:{identifier}"));
    let links: Vec<Url> = res
        .links
        .iter()
        .filter(|link| {
            if let Some(type_) = &link.kind {
                type_.starts_with("application/")
            } else {
                false
            }
        })
        .filter_map(|l| l.href.clone())
        .collect();

    for l in links {
        let object = ObjectId::<Kind>::from(l).dereference(data).await;
        match object {
            Ok(obj) => return Ok(obj),
            Err(error) => debug!(%error, "Failed to dereference link"),
        }
    }
    Err(WebFingerError::NoValidLink.into_crate_error().into())
}

The Webfinger logic takes the user account from the GET parameter “resource” and sinks the domain directly into the…

Record
GHSA-7723-35v7-qcxw
CVSS 3.1
4.0 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
NVD 4.0

Lemmy, a link aggregator and forum for the fediverse, is vulnerable to server-side request forgery via a dependency on activitypub_federation, a framework for ActivityPub federation in Rust. This vulnerability, which is present in versions 0.6.2 and prior of activitypub_federation and versions 0.19.8 and prior of Lemmy, 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. As of time of publication, a fix has not been made available.

Record
CVE-2025-25194
CVSS 3.1
4.0 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
OSV 4.0

Server-Side Request Forgery (SSRF) in activitypub_federation

Lemmy, a link aggregator and forum for the fediverse, is vulnerable to server-side request forgery via a dependency on activitypub_federation, a framework for ActivityPub federation in Rust. This vulnerability, which is present in versions 0.6.2 and prior of activitypub_federation and versions 0.19.8 and prior of Lemmy, 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. As of time of publication, a fix has not been made available.

Record
CVE-2025-25194
CVSS 3.1
4.0 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
OSVGHSA-7723-35v7-qcxw 4.0

Server-Side Request Forgery (SSRF) in activitypub_federation

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):

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):

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);

    let res: Webfinger = fetch_object_http_with_accept(
        &Url::parse(&fetch_url).map_err(Error::UrlParse)?,
        data,
        &WEBFINGER_CONTENT_TYPE,
    )
    .await?
    .object;

    debug_assert_eq!(res.subject, format!("acct:{identifier}"));
    let links: Vec<Url> = res
        .links
        .iter()
        .filter(|link| {
            if let Some(type_) = &link.kind {
                type_.starts_with("application/")
            } else {
                false
            }
        })
        .filter_map(|l| l.href.clone())
        .collect();

    for l in links {
        let object = ObjectId::<Kind>::from(l).dereference(data).await;
        match object {
            Ok(obj) => return Ok(obj),
            Err(error) => debug!(%error, "Failed to dereference link"),
        }
    }
    Err(WebFingerError::NoValidLink.into_crate_error().into())
}

The Webfinger logic takes the user account from the GET parameter “resource” and sinks the domain directly into the…

Record
GHSA-7723-35v7-qcxw
CVSS 3.1
4.0 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
activitypub_federation
crates.io
through 0.6.2 None known

History

History
RecordedChangedSources
aliasesEUVD
first indexedCVE List, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2025-25194 is a medium vulnerability (CVSS 4.0) in Lemmynet Lemmy, published February 10, 2025. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.42%, the 36th percentile. No source names a fixed version.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open