VYPR
High severityNVD Advisory· Published Mar 6, 2026· Updated Apr 28, 2026

CVE-2026-29178

CVE-2026-29178

Description

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. Prior to version 0.19.16, the GET /api/v4/image/{filename} endpoint is vulnerable to unauthenticated SSRF through parameter injection in the file_type query parameter. An attacker can inject arbitrary query parameters into the internal request to pict-rs, including the proxy parameter which causes pict-rs to fetch arbitrary URLs. This issue has been patched in version 0.19.16.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
lemmy_routescrates.io
< 0.19.160.19.16

Affected products

1

Patches

1
f47a03f56d17

[v0.19] Adding tests for image file_type (#6368)

https://github.com/LemmyNet/lemmyDessalinesFeb 27, 2026via ghsa
1 file changed · +54 6
  • crates/routes/src/images.rs+54 6 modified
    @@ -24,7 +24,7 @@ use lemmy_utils::{
     };
     use reqwest::Body;
     use reqwest_middleware::{ClientWithMiddleware, RequestBuilder};
    -use serde::{Deserialize, Serialize};
    +use serde::Deserialize;
     use std::{str::FromStr, time::Duration};
     use strum::{Display, EnumString};
     use url::Url;
    @@ -61,7 +61,7 @@ impl ProcessUrl for PictrsGetParams {
           format!("{}image/original/{}", pictrs_url, src)
         } else {
           // Take file type from name, or jpg if nothing is given
    -      let format = file_type(self.format.clone(), src).unwrap_or(PictrsFileType::Jpg);
    +      let format = file_type(self.format.clone(), src).unwrap_or_default();
     
           let mut url = format!("{}image/process.{}?src={}", pictrs_url, format, src);
     
    @@ -73,13 +73,13 @@ impl ProcessUrl for PictrsGetParams {
       }
     }
     
    -#[derive(EnumString, Display, Debug, Serialize, PartialEq)]
    -#[serde(rename_all = "snake_case")]
    -#[strum(ascii_case_insensitive)]
    +#[derive(EnumString, Display, PartialEq, Debug, Default)]
    +#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
     enum PictrsFileType {
       Apng,
       Avif,
       Gif,
    +  #[default]
       Jpg,
       Jxl,
       Png,
    @@ -108,7 +108,7 @@ impl ProcessUrl for ImageProxyParams {
           format!("{}image/original?proxy={}", pictrs_url, proxy_url)
         } else {
           // Take file type from name, or jpg if nothing is given
    -      let format = file_type(self.format.clone(), proxy_url).unwrap_or(PictrsFileType::Jpg);
    +      let format = file_type(self.format.clone(), proxy_url).unwrap_or_default();
     
           let mut url = format!("{}image/process.{}?proxy={}", pictrs_url, format, proxy_url);
     
    @@ -345,3 +345,51 @@ where
         std::pin::Pin::new(&mut self.rx).poll_recv(cx)
       }
     }
    +
    +#[cfg(test)]
    +mod tests {
    +  use crate::images::{file_type, PictrsFileType};
    +  use lemmy_utils::error::LemmyResult;
    +
    +  #[tokio::test]
    +  async fn image_file_type_tests() -> LemmyResult<()> {
    +    // Make sure files type outputs are getting lower-cased
    +    assert_eq!(PictrsFileType::Jpg.to_string(), "jpg".to_string());
    +
    +    let file_url = "a8a7f07f-3ef2-40fa-849c-ae952f68f3ec.jpg";
    +
    +    // Make sure wrong-cased file type requests are okay
    +    assert_eq!(
    +      PictrsFileType::Jpg,
    +      file_type(Some("JPg".to_string()), file_url)?
    +    );
    +
    +    // Make sure wrong file type requests are okay with unwrap_or_default
    +    assert_eq!(
    +      PictrsFileType::Jpg,
    +      file_type(Some("jpeg".to_string()), file_url).unwrap_or_default()
    +    );
    +    assert_eq!(
    +      PictrsFileType::Jpg,
    +      file_type(Some("nonsense".to_string()), file_url).unwrap_or_default()
    +    );
    +
    +    // Make sure missing file type requests are okay
    +    assert_eq!(PictrsFileType::Jpg, file_type(None, file_url)?);
    +
    +    // jpeg
    +    let file_url = "a8a7f07f-3ef2-40fa-849c-ae952f68f3ec.jpeg";
    +
    +    // Make sure jpeg one is okay
    +    assert_eq!(
    +      PictrsFileType::Jpg,
    +      file_type(None, file_url).unwrap_or_default()
    +    );
    +
    +    // Make sure proxy ones are okay
    +    let proxy_url = "https://test.tld/pictrs/image/6d3b2f3f-7b29-4d9a-868e-b269423f4d6c.WEbP";
    +    assert_eq!(PictrsFileType::Webp, file_type(None, proxy_url)?);
    +
    +    Ok(())
    +  }
    +}
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

4

News mentions

0

No linked articles in our index yet.