Common Weakness Enumeration

CWE-918

Allowed

Server-Side Request Forgery (SSRF)

Abstraction: Base · Status: Incomplete

The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

6551 vulnerabilities reference this CWE, most recent first.

GHSA-PC36-QWJQ-X68C

Vulnerability from github – Published: 2026-10-07 20:42 – Updated: 2026-10-07 20:42
VLAI
Summary
Docling has SSRF guard bypass in remote resource fetching (DNS rebinding / multi-record resolution; no IP validation in HTML render mode)
Details

Summary

When remote fetching is enabled (enable_remote_fetch=True, together with fetch_images=True or HTML render_page=True), docling's protection against requests to private and loopback addresses can be bypassed.

  • The URL check resolves the host name once, to a single IPv4 address. The HTTP request then resolves it again. A name that returns a public A record together with an internal AAAA record, or one that changes its answer between the two lookups (DNS rebinding), reaches internal addresses.
  • The check and the HTTP request parse the URL differently. With a backslash in the authority, such as http://127.0.0.1:8080\@1.1.1.1/x.png, the check validates 1.1.1.1 while the HTTP client connects to 127.0.0.1:8080.
  • In HTML browser-rendering mode (render_page=True), requests made by the page are allowed for any http(s) URL without an IP check.

Details

  • validate_url_safety in docling/backend/utils/image_resource_loader.py calls socket.gethostbyname(), which returns one IPv4 address. It checks that address and then passes the original URL string to requests, which parses it again with urllib3 and resolves the name independently through getaddrinfo. urllib.parse treats a backslash in the authority as part of the host section, while urllib3 ends the authority there, so the two can pick different hosts. This loader is shared by the HTML, Markdown, AsciiDoc, OpenDocument and JATS backends.
  • docling/backend/html_backend.py routes browser requests in render mode. When enable_remote_fetch is set, it continues any http(s) request, including iframes and images, without resolving or checking the destination.

JavaScript is disabled during rendering, so the browser path can only show internal responses passively in the page screenshot. It cannot read them and send them elsewhere.

Affected configurations

  • Affected: callers that enable enable_remote_fetch (CLI: --html-image-fetch remote or all) and process untrusted documents.
  • Not affected: the default configuration (enable_remote_fetch=False).

The main-URL fetch for DocumentConverter.convert("https://...") is implemented in docling-core and is tracked there.

Impact

Requests from the converting host to internal services such as cloud metadata endpoints and loopback services. Response content is exposed only when it decodes as an image or is rendered into the page screenshot.

Patches

Fixed in docling 2.132.0 by #4420. The image loader now resolves the host once, requires every resolved address (IPv4 and IPv6, including IPv4-mapped, 6to4 and NAT64 forms) to be globally routable, and connects to one of the validated addresses, using the same parsed host for the check and the connection. Remote requests made during HTML browser rendering are downloaded by the same loader, and the browser itself stays offline. When a proxy is configured through environment variables, requests go through the proxy, which is then responsible for filtering destinations.

Workarounds

Upgrade to 2.132.0. For older versions:

Keep enable_remote_fetch=False for untrusted documents, or block egress to private, link-local and loopback ranges at the network level.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "docling"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.91.0"
            },
            {
              "fixed": "2.132.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "docling-slim"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.92.0"
            },
            {
              "fixed": "2.132.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-105743"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-367",
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-07T20:42:19Z",
    "nvd_published_at": "2026-10-05T22:16:57Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nWhen remote fetching is enabled (`enable_remote_fetch=True`, together with `fetch_images=True` or HTML `render_page=True`), docling\u0027s protection against requests to private and loopback addresses can be bypassed.\n\n- The URL check resolves the host name once, to a single IPv4 address. The HTTP request then resolves it again. A name that returns a public A record together with an internal AAAA record, or one that changes its answer between the two lookups (DNS rebinding), reaches internal addresses.\n- The check and the HTTP request parse the URL differently. With a backslash in the authority, such as `http://127.0.0.1:8080\\@1.1.1.1/x.png`, the check validates `1.1.1.1` while the HTTP client connects to `127.0.0.1:8080`.\n- In HTML browser-rendering mode (`render_page=True`), requests made by the page are allowed for any `http(s)` URL without an IP check.\n\n### Details\n\n- `validate_url_safety` in `docling/backend/utils/image_resource_loader.py` calls `socket.gethostbyname()`, which returns one IPv4 address. It checks that address and then passes the original URL string to `requests`, which parses it again with urllib3 and resolves the name independently through `getaddrinfo`. `urllib.parse` treats a backslash in the authority as part of the host section, while urllib3 ends the authority there, so the two can pick different hosts. This loader is shared by the HTML, Markdown, AsciiDoc, OpenDocument and JATS backends.\n- `docling/backend/html_backend.py` routes browser requests in render mode. When `enable_remote_fetch` is set, it continues any `http(s)` request, including iframes and images, without resolving or checking the destination.\n\nJavaScript is disabled during rendering, so the browser path can only show internal responses passively in the page screenshot. It cannot read them and send them elsewhere.\n\n### Affected configurations\n\n- Affected: callers that enable `enable_remote_fetch` (CLI: `--html-image-fetch remote` or `all`) and process untrusted documents.\n- Not affected: the default configuration (`enable_remote_fetch=False`).\n\nThe main-URL fetch for `DocumentConverter.convert(\"https://...\")` is implemented in docling-core and is tracked there.\n\n### Impact\n\nRequests from the converting host to internal services such as cloud metadata endpoints and loopback services. Response content is exposed only when it decodes as an image or is rendered into the page screenshot.\n\n### Patches\n\nFixed in docling 2.132.0 by [#4420](https://github.com/docling-project/docling/pull/4420). The image loader now resolves the host once, requires every resolved address (IPv4 and IPv6, including IPv4-mapped, 6to4 and NAT64 forms) to be globally routable, and connects to one of the validated addresses, using the same parsed host for the check and the connection. Remote requests made during HTML browser rendering are downloaded by the same loader, and the browser itself stays offline. When a proxy is configured through environment variables, requests go through the proxy, which is then responsible for filtering destinations.\n\n### Workarounds\n\nUpgrade to 2.132.0. For older versions:\n\nKeep `enable_remote_fetch=False` for untrusted documents, or block egress to private, link-local and loopback ranges at the network level.",
  "id": "GHSA-pc36-qwjq-x68c",
  "modified": "2026-10-07T20:42:19Z",
  "published": "2026-10-07T20:42:19Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/docling-project/docling/security/advisories/GHSA-pc36-qwjq-x68c"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-105743"
    },
    {
      "type": "WEB",
      "url": "https://github.com/docling-project/docling/pull/4420"
    },
    {
      "type": "WEB",
      "url": "https://github.com/docling-project/docling/commit/5e469137f275ffc443306a30d12a3a45bceb80fb"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/docling-project/docling"
    },
    {
      "type": "WEB",
      "url": "https://github.com/docling-project/docling/releases/tag/v2.132.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Docling has SSRF guard bypass in remote resource fetching (DNS rebinding / multi-record resolution; no IP validation in HTML render mode)"
}

GHSA-PC6F-259W-W3J6

Vulnerability from github – Published: 2022-10-04 00:00 – Updated: 2024-09-27 21:17
VLAI
Summary
Heartex - Label Studio Community Edition vulnerable to SSRF in the Data Import module
Details

A Server Side Request Forgery (SSRF) in the Data Import module in Heartex - Label Studio Community Edition versions 1.5.0 and earlier allows an authenticated user to access arbitrary files on the system. Furthermore, self-registration is enabled by default in these versions of Label Studio enabling a remote attacker to create a new account and then exploit the SSRF. This issue is fixed in version 1.6.0.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "label-studio"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.6.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-36551"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-10-04T21:57:17Z",
    "nvd_published_at": "2022-10-03T12:15:00Z",
    "severity": "HIGH"
  },
  "details": "A Server Side Request Forgery (SSRF) in the Data Import module in Heartex - Label Studio Community Edition versions 1.5.0 and earlier allows an authenticated user to access arbitrary files on the system. Furthermore, self-registration is enabled by default in these versions of Label Studio enabling a remote attacker to create a new account and then exploit the SSRF. This issue is fixed in version 1.6.0.",
  "id": "GHSA-pc6f-259w-w3j6",
  "modified": "2024-09-27T21:17:52Z",
  "published": "2022-10-04T00:00:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-36551"
    },
    {
      "type": "WEB",
      "url": "https://github.com/heartexlabs/label-studio/pull/2840"
    },
    {
      "type": "WEB",
      "url": "https://github.com/heartexlabs/label-studio/commit/501142cb815ac964b0c600c491885b67386870c2"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/heartexlabs/label-studio"
    },
    {
      "type": "WEB",
      "url": "https://github.com/heartexlabs/label-studio/releases/tag/1.6.0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/label-studio/PYSEC-2022-300.yaml"
    },
    {
      "type": "WEB",
      "url": "http://heartex.com"
    },
    {
      "type": "WEB",
      "url": "http://labelstud.io"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/171548/Label-Studio-1.5.0-Server-Side-Request-Forgery.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Heartex - Label Studio Community Edition vulnerable to SSRF in the Data Import module"
}

GHSA-PC74-V89M-R259

Vulnerability from github – Published: 2025-09-05 15:31 – Updated: 2026-04-01 18:36
VLAI
Details

Server-Side Request Forgery (SSRF) vulnerability in aitool Ai Auto Tool Content Writing Assistant (Gemini Writer, ChatGPT ) All in One allows Server Side Request Forgery. This issue affects Ai Auto Tool Content Writing Assistant (Gemini Writer, ChatGPT ) All in One: from n/a through 2.2.6.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-58829"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-09-05T14:15:55Z",
    "severity": "MODERATE"
  },
  "details": "Server-Side Request Forgery (SSRF) vulnerability in aitool Ai Auto Tool Content Writing Assistant (Gemini Writer, ChatGPT ) All in One allows Server Side Request Forgery. This issue affects Ai Auto Tool Content Writing Assistant (Gemini Writer, ChatGPT ) All in One: from n/a through 2.2.6.",
  "id": "GHSA-pc74-v89m-r259",
  "modified": "2026-04-01T18:36:05Z",
  "published": "2025-09-05T15:31:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-58829"
    },
    {
      "type": "WEB",
      "url": "https://patchstack.com/database/wordpress/plugin/ai-auto-tool/vulnerability/wordpress-ai-auto-tool-content-writing-assistant-gemini-writer-chatgpt-all-in-one-plugin-2-2-6-server-side-request-forgery-ssrf-vulnerability?_s_id=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-PC7X-R4C4-7QQW

Vulnerability from github – Published: 2022-06-20 00:00 – Updated: 2022-06-29 00:00
VLAI
Details

In Recipes, versions 0.9.1 through 1.2.5 are vulnerable to Server Side Request Forgery (SSRF), in the “Import Recipe” functionality. When an attacker enters the localhost URL, a low privileged attacker can access/read the internal file system to access sensitive information.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-23071"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-06-19T11:15:00Z",
    "severity": "MODERATE"
  },
  "details": "In Recipes, versions 0.9.1 through 1.2.5 are vulnerable to Server Side Request Forgery (SSRF), in the \u201cImport Recipe\u201d functionality. When an attacker enters the localhost URL, a low privileged attacker can access/read the internal file system to access sensitive information.",
  "id": "GHSA-pc7x-r4c4-7qqw",
  "modified": "2022-06-29T00:00:28Z",
  "published": "2022-06-20T00:00:34Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-23071"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TandoorRecipes/recipes/commit/d48fe26a3529cc1ee903ffb2758dfd8f7efaba8c"
    },
    {
      "type": "WEB",
      "url": "https://www.mend.io/vulnerability-database/CVE-2022-23071"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-PCRP-7G2P-Q7PJ

Vulnerability from github – Published: 2024-11-07 18:31 – Updated: 2024-11-07 21:31
VLAI
Details

An issue was discovered in Logpoint before 7.5.0. Server-Side Request Forgery (SSRF) on SOAR can be used to leak Logpoint's API Token leading to authentication bypass.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-48951"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-11-07T17:15:08Z",
    "severity": "HIGH"
  },
  "details": "An issue was discovered in Logpoint before 7.5.0. Server-Side Request Forgery (SSRF) on SOAR can be used to leak Logpoint\u0027s API Token leading to authentication bypass.",
  "id": "GHSA-pcrp-7g2p-q7pj",
  "modified": "2024-11-07T21:31:43Z",
  "published": "2024-11-07T18:31:23Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-48951"
    },
    {
      "type": "WEB",
      "url": "https://docs.logpoint.com/docs/whats-new-in-logpoint/en/latest"
    },
    {
      "type": "WEB",
      "url": "https://servicedesk.logpoint.com/hc/en-us/articles/21968916591261-Server-Side-Request-Forgery-SSRF-on-SOAR-results-in-authentication-bypass"
    },
    {
      "type": "WEB",
      "url": "https://servicedesk.logpoint.com/hc/en-us/sections/7201103730845-Product-Security"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-PCW6-8CPC-9HVX

Vulnerability from github – Published: 2026-09-07 06:30 – Updated: 2026-09-07 06:30
VLAI
Details

A weakness has been identified in projeto-siga siga up to 11.1.1. Affected by this issue is the function DownloadExterno.getUrl of the file sigaex/src/main/java/br/gov/jfrj/siga/vraptor/ExUtilController.java of the component HTML-to-PDF Endpoint. This manipulation of the argument html causes server-side request forgery. The attack may be initiated remotely. The exploit has been made available to the public and could be used for attacks. The project was informed of the problem early through an issue report but has not responded yet.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-86273"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-07T06:17:23Z",
    "severity": "MODERATE"
  },
  "details": "A weakness has been identified in projeto-siga siga up to 11.1.1. Affected by this issue is the function DownloadExterno.getUrl of the file sigaex/src/main/java/br/gov/jfrj/siga/vraptor/ExUtilController.java of the component HTML-to-PDF Endpoint. This manipulation of the argument html causes server-side request forgery. The attack may be initiated remotely. The exploit has been made available to the public and could be used for attacks. The project was informed of the problem early through an issue report but has not responded yet.",
  "id": "GHSA-pcw6-8cpc-9hvx",
  "modified": "2026-09-07T06:30:24Z",
  "published": "2026-09-07T06:30:24Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-86273"
    },
    {
      "type": "WEB",
      "url": "https://github.com/projeto-siga/siga/issues/2492"
    },
    {
      "type": "WEB",
      "url": "https://github.com/projeto-siga/siga"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/cve/CVE-2026-86273"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/submit/904863"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/vuln/399434"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/vuln/399434/cti"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:L/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",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-PCX4-V3RH-GQ5X

Vulnerability from github – Published: 2026-06-24 09:30 – Updated: 2026-06-24 09:30
VLAI
Details

The WP Meta SEO plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 4.5.18 via the 'new_link' parameter. This makes it possible for authenticated attackers, with contributor-level access and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services. The HTTP response status from outbound requests is reflected back in the AJAX JSON response as status_code, providing an enumeration oracle usable for probing internal hosts and cloud metadata services.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-11370"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-06-24T07:16:26Z",
    "severity": "MODERATE"
  },
  "details": "The WP Meta SEO plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 4.5.18 via the \u0027new_link\u0027 parameter. This makes it possible for authenticated attackers, with contributor-level access and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services. The HTTP response status from outbound requests is reflected back in the AJAX JSON response as status_code, providing an enumeration oracle usable for probing internal hosts and cloud metadata services.",
  "id": "GHSA-pcx4-v3rh-gq5x",
  "modified": "2026-06-24T09:30:45Z",
  "published": "2026-06-24T09:30:45Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-11370"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wp-meta-seo/tags/4.5.18/inc/class.metaseo-admin.php#L4783"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wp-meta-seo/tags/4.5.18/inc/class.metaseo-broken-link-table.php#L1138"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wp-meta-seo/tags/4.5.18/inc/class.metaseo-broken-link-table.php#L2013"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/2a6e37c1-aaac-4642-bace-234bbc4f6c38?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-PF3H-QJGV-VCPR

Vulnerability from github – Published: 2026-04-03 21:51 – Updated: 2026-07-17 16:18
VLAI
Summary
vLLM: Server-Side Request Forgery (SSRF) in `download_bytes_from_url `
Details

Summary

A Server Side Request Forgery (SSRF) vulnerability in download_bytes_from_url allows any actor who can control batch input JSON to make the vLLM batch runner issue arbitrary HTTP/HTTPS requests from the server, without any URL validation or domain restrictions.

This can be used to target internal services (e.g. cloud metadata endpoints or internal HTTP APIs) reachable from the vLLM host.


Details

Vulnerable component

The vulnerable logic is in the batch runner entrypoint vllm/entrypoints/openai/run_batch.py, function download_bytes_from_url:

# run_batch.py Lines 442-482
async def download_bytes_from_url(url: str) -> bytes:
    """
    Download data from a URL or decode from a data URL.

    Args:
        url: Either an HTTP/HTTPS URL or a data URL (data:...;base64,...)

    Returns:
        Data as bytes
    """
    parsed = urlparse(url)

    # Handle data URLs (base64 encoded)
    if parsed.scheme == "data":
        # Format: data:...;base64,<base64_data>
        if "," in url:
            header, data = url.split(",", 1)
            if "base64" in header:
                return base64.b64decode(data)
            else:
                raise ValueError(f"Unsupported data URL encoding: {header}")
        else:
            raise ValueError(f"Invalid data URL format: {url}")

    # Handle HTTP/HTTPS URLs
    elif parsed.scheme in ("http", "https"):
        async with (
            aiohttp.ClientSession() as session,
            session.get(url) as resp,
        ):
            if resp.status != 200:
                raise Exception(
                    f"Failed to download data from URL: {url}. Status: {resp.status}"
                )
            return await resp.read()

    else:
        raise ValueError(
            f"Unsupported URL scheme: {parsed.scheme}. "
            "Supported schemes: http, https, data"
        )

Key properties:

  • The function only parses the URL to dispatch on the scheme (data, http, https).
  • For http / https, it directly calls session.get(url) on the provided string.
  • There is no validation of:
  • hostname or IP address,
  • whether the target is internal or external,
  • port number,
  • path, query, or redirect target.
  • This is in contrast to the multimodal media path (MediaConnector), which implements an explicit domain allowlist. download_bytes_from_url does not reuse that protection.

URL controllability

The url argument is fully controlled by batch input JSON via the file_url field of BatchTranscriptionRequest / BatchTranslationRequest.

  1. Batch request body type:
# run_batch.py Line 67-80
class BatchTranscriptionRequest(TranscriptionRequest):
    """
    Batch transcription request that uses file_url instead of file.

    This class extends TranscriptionRequest but replaces the file field
    with file_url to support batch processing from audio files written in JSON format.
    """

    file_url: str = Field(
        ...,
        description=(
            "Either a URL of the audio or a data URL with base64 encoded audio data. "
        ),
    )
# run_batch.py Line 98-111
class BatchTranslationRequest(TranslationRequest):
    """
    Batch translation request that uses file_url instead of file.

    This class extends TranslationRequest but replaces the file field
    with file_url to support batch processing from audio files written in JSON format.
    """

    file_url: str = Field(
        ...,
        description=(
            "Either a URL of the audio or a data URL with base64 encoded audio data. "
        ),
    )

There is no restriction on the domain, IP, or port of file_url in these models.

  1. Batch input is parsed directly from the batch file:
# run_batch.py Line 139-179
class BatchRequestInput(OpenAIBaseModel):
    ...
    url: str
    body: BatchRequestInputBody
    @field_validator("body", mode="plain")
    @classmethod
    def check_type_for_url(cls, value: Any, info: ValidationInfo):
        url: str = info.data["url"]
        ...
        if url == "/v1/audio/transcriptions":
            return BatchTranscriptionRequest.model_validate(value)
        if url == "/v1/audio/translations":
            return BatchTranslationRequest.model_validate(value)
# run_batch.py Line 770-781
   logger.info("Reading batch from %s...", args.input_file)

    # Submit all requests in the file to the engine "concurrently".
    response_futures: list[Awaitable[BatchRequestOutput]] = []
    for request_json in (await read_file(args.input_file)).strip().split("\n"):
        # Skip empty lines.
        request_json = request_json.strip()
        if not request_json:
            continue

        request = BatchRequestInput.model_validate_json(request_json)

The batch runner reads each line of the input file (args.input_file), parses it as JSON, and constructs a BatchTranscriptionRequest / BatchTranslationRequest. Whatever file_url appears in that JSON line becomes batch_request_body.file_url.

  1. file_url is passed directly into download_bytes_from_url:
# run_batch.py Line 610-623
def wrapper(handler_fn: Callable):
        async def transcription_wrapper(
            batch_request_body: (BatchTranscriptionRequest | BatchTranslationRequest),
        ) -> (
            TranscriptionResponse
            | TranscriptionResponseVerbose
            | TranslationResponse
            | TranslationResponseVerbose
            | ErrorResponse
        ):
            try:
                # Download data from URL
                audio_data = await download_bytes_from_url(batch_request_body.file_url)

So the data flow is:

  1. Attacker supplies JSON line in the batch input file with arbitrary body.file_url.
  2. BatchRequestInput / BatchTranscriptionRequest / BatchTranslationRequest parse that JSON and store file_url verbatim.
  3. make_transcription_wrapper calls download_bytes_from_url(batch_request_body.file_url).
  4. download_bytes_from_url’s HTTP/HTTPS branch issues aiohttp.ClientSession().get(url) to that attacker-controlled URL with no further validation.

This is a classic SSRF pattern: a server-side component makes arbitrary HTTP requests to a URL string taken from untrusted input.

Comparison with safer code

The project already contains a safer URL-handling path for multimodal media in vllm/multimodal/media/connector.py, which demonstrates the intent to mitigate SSRF via domain allowlists and URL normalization:

# connector.py Lines 169-189
 def load_from_url(
        self,
        url: str,
        media_io: MediaIO[_M],
        *,
        fetch_timeout: int | None = None,
    ) -> _M:  # type: ignore[type-var]
        url_spec = parse_url(url)

        if url_spec.scheme and url_spec.scheme.startswith("http"):
            self._assert_url_in_allowed_media_domains(url_spec)

            connection = self.connection
            data = connection.get_bytes(
                url_spec.url,
                timeout=fetch_timeout,
                allow_redirects=envs.VLLM_MEDIA_URL_ALLOW_REDIRECTS,
            )

            return media_io.load_bytes(data)

and:

# connector.py Lines 158-167
  def _assert_url_in_allowed_media_domains(self, url_spec: Url) -> None:
        if (
            self.allowed_media_domains
            and url_spec.hostname not in self.allowed_media_domains
        ):
            raise ValueError(
                f"The URL must be from one of the allowed domains: "
                f"{self.allowed_media_domains}. Input URL domain: "
                f"{url_spec.hostname}"
            )

download_bytes_from_url does not reuse this allowlist or any equivalent validation, even though it also fetches user-provided URLs.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "vllm"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.16.0"
            },
            {
              "fixed": "0.19.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34753"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-03T21:51:00Z",
    "nvd_published_at": "2026-04-06T16:16:36Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nA Server Side Request Forgery (SSRF) vulnerability in `download_bytes_from_url` allows any actor who can control batch input JSON to make the vLLM batch runner issue arbitrary HTTP/HTTPS requests from the server, without any URL validation or domain restrictions.\n\nThis can be used to target internal services (e.g. cloud metadata endpoints or internal HTTP APIs) reachable from the vLLM host.\n\n------\n\n### Details\n\n#### Vulnerable component\n\nThe vulnerable logic is in the batch runner entrypoint `vllm/entrypoints/openai/run_batch.py`, function `download_bytes_from_url`:\n\n```\n# run_batch.py Lines 442-482\nasync def download_bytes_from_url(url: str) -\u003e bytes:\n    \"\"\"\n    Download data from a URL or decode from a data URL.\n\n    Args:\n        url: Either an HTTP/HTTPS URL or a data URL (data:...;base64,...)\n\n    Returns:\n        Data as bytes\n    \"\"\"\n    parsed = urlparse(url)\n\n    # Handle data URLs (base64 encoded)\n    if parsed.scheme == \"data\":\n        # Format: data:...;base64,\u003cbase64_data\u003e\n        if \",\" in url:\n            header, data = url.split(\",\", 1)\n            if \"base64\" in header:\n                return base64.b64decode(data)\n            else:\n                raise ValueError(f\"Unsupported data URL encoding: {header}\")\n        else:\n            raise ValueError(f\"Invalid data URL format: {url}\")\n\n    # Handle HTTP/HTTPS URLs\n    elif parsed.scheme in (\"http\", \"https\"):\n        async with (\n            aiohttp.ClientSession() as session,\n            session.get(url) as resp,\n        ):\n            if resp.status != 200:\n                raise Exception(\n                    f\"Failed to download data from URL: {url}. Status: {resp.status}\"\n                )\n            return await resp.read()\n\n    else:\n        raise ValueError(\n            f\"Unsupported URL scheme: {parsed.scheme}. \"\n            \"Supported schemes: http, https, data\"\n        )\n```\n\nKey properties:\n\n- The function only parses the URL to dispatch on the scheme (`data`, `http`, `https`).\n- For `http` / `https`, it directly calls `session.get(url)` on the provided string.\n- There is no validation of:\n  - hostname or IP address,\n  - whether the target is internal or external,\n  - port number,\n  - path, query, or redirect target.\n- This is in contrast to the multimodal media path (`MediaConnector`), which implements an explicit domain allowlist. `download_bytes_from_url` does not reuse that protection.\n\n#### URL controllability\n\nThe `url` argument is fully controlled by batch input JSON via the `file_url` field of `BatchTranscriptionRequest` / `BatchTranslationRequest`.\n\n1. Batch request body type:\n\n```\n# run_batch.py Line 67-80\nclass BatchTranscriptionRequest(TranscriptionRequest):\n    \"\"\"\n    Batch transcription request that uses file_url instead of file.\n\n    This class extends TranscriptionRequest but replaces the file field\n    with file_url to support batch processing from audio files written in JSON format.\n    \"\"\"\n\n    file_url: str = Field(\n        ...,\n        description=(\n            \"Either a URL of the audio or a data URL with base64 encoded audio data. \"\n        ),\n    )\n```\n\n```\n# run_batch.py Line 98-111\nclass BatchTranslationRequest(TranslationRequest):\n    \"\"\"\n    Batch translation request that uses file_url instead of file.\n\n    This class extends TranslationRequest but replaces the file field\n    with file_url to support batch processing from audio files written in JSON format.\n    \"\"\"\n\n    file_url: str = Field(\n        ...,\n        description=(\n            \"Either a URL of the audio or a data URL with base64 encoded audio data. \"\n        ),\n    )\n```\n\nThere is no restriction on the domain, IP, or port of `file_url` in these models.\n\n1. Batch input is parsed directly from the batch file:\n\n```\n# run_batch.py Line 139-179\nclass BatchRequestInput(OpenAIBaseModel):\n    ...\n    url: str\n    body: BatchRequestInputBody\n    @field_validator(\"body\", mode=\"plain\")\n    @classmethod\n    def check_type_for_url(cls, value: Any, info: ValidationInfo):\n        url: str = info.data[\"url\"]\n        ...\n        if url == \"/v1/audio/transcriptions\":\n            return BatchTranscriptionRequest.model_validate(value)\n        if url == \"/v1/audio/translations\":\n            return BatchTranslationRequest.model_validate(value)\n```\n\n```\n# run_batch.py Line 770-781\n   logger.info(\"Reading batch from %s...\", args.input_file)\n\n    # Submit all requests in the file to the engine \"concurrently\".\n    response_futures: list[Awaitable[BatchRequestOutput]] = []\n    for request_json in (await read_file(args.input_file)).strip().split(\"\\n\"):\n        # Skip empty lines.\n        request_json = request_json.strip()\n        if not request_json:\n            continue\n\n        request = BatchRequestInput.model_validate_json(request_json)\n```\n\nThe batch runner reads each line of the input file (`args.input_file`), parses it as JSON, and constructs a `BatchTranscriptionRequest` / `BatchTranslationRequest`. Whatever `file_url` appears in that JSON line becomes `batch_request_body.file_url`.\n\n1. `file_url` is passed directly into `download_bytes_from_url`:\n\n```\n# run_batch.py Line 610-623\ndef wrapper(handler_fn: Callable):\n        async def transcription_wrapper(\n            batch_request_body: (BatchTranscriptionRequest | BatchTranslationRequest),\n        ) -\u003e (\n            TranscriptionResponse\n            | TranscriptionResponseVerbose\n            | TranslationResponse\n            | TranslationResponseVerbose\n            | ErrorResponse\n        ):\n            try:\n                # Download data from URL\n                audio_data = await download_bytes_from_url(batch_request_body.file_url)\n```\n\nSo the data flow is:\n\n1. Attacker supplies JSON line in the batch input file with arbitrary `body.file_url`.\n2. `BatchRequestInput` / `BatchTranscriptionRequest` / `BatchTranslationRequest` parse that JSON and store `file_url` verbatim.\n3. `make_transcription_wrapper` calls `download_bytes_from_url(batch_request_body.file_url)`.\n4. `download_bytes_from_url`\u2019s HTTP/HTTPS branch issues `aiohttp.ClientSession().get(url)` to that attacker-controlled URL with no further validation.\n\nThis is a classic SSRF pattern: a server-side component makes arbitrary HTTP requests to a URL string taken from untrusted input.\n\n#### Comparison with safer code\n\nThe project already contains a safer URL-handling path for multimodal media in `vllm/multimodal/media/connector.py`, which demonstrates the intent to mitigate SSRF via domain allowlists and URL normalization:\n\n```\n# connector.py Lines 169-189\n def load_from_url(\n        self,\n        url: str,\n        media_io: MediaIO[_M],\n        *,\n        fetch_timeout: int | None = None,\n    ) -\u003e _M:  # type: ignore[type-var]\n        url_spec = parse_url(url)\n\n        if url_spec.scheme and url_spec.scheme.startswith(\"http\"):\n            self._assert_url_in_allowed_media_domains(url_spec)\n\n            connection = self.connection\n            data = connection.get_bytes(\n                url_spec.url,\n                timeout=fetch_timeout,\n                allow_redirects=envs.VLLM_MEDIA_URL_ALLOW_REDIRECTS,\n            )\n\n            return media_io.load_bytes(data)\n```\n\nand:\n\n```\n# connector.py Lines 158-167\n  def _assert_url_in_allowed_media_domains(self, url_spec: Url) -\u003e None:\n        if (\n            self.allowed_media_domains\n            and url_spec.hostname not in self.allowed_media_domains\n        ):\n            raise ValueError(\n                f\"The URL must be from one of the allowed domains: \"\n                f\"{self.allowed_media_domains}. Input URL domain: \"\n                f\"{url_spec.hostname}\"\n            )\n```\n\n`download_bytes_from_url` does not reuse this allowlist or any equivalent validation, even though it also fetches user-provided URLs.",
  "id": "GHSA-pf3h-qjgv-vcpr",
  "modified": "2026-07-17T16:18:19Z",
  "published": "2026-04-03T21:51:00Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-pf3h-qjgv-vcpr"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34753"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/pull/38482"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vllm-project/vllm/commit/57861ae48d3493fa48b4d7d830b7ec9f995783e7"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-pf3h-qjgv-vcpr"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/vllm/PYSEC-2026-3410.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/vllm-project/vllm"
    },
    {
      "type": "WEB",
      "url": "https://pypi.org/project/vllm"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "vLLM: Server-Side Request Forgery (SSRF) in `download_bytes_from_url `"
}

GHSA-PF5R-4CPX-XCXM

Vulnerability from github – Published: 2022-05-24 19:03 – Updated: 2022-05-24 19:03
VLAI
Details

IBM Jazz Foundation and IBM Engineering products are vulnerable to server-side request forgery (SSRF). This may allow an authenticated attacker to send unauthorized requests from the system, potentially leading to network enumeration or facilitating other attacks. IBM X-Force ID: 194596.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-20347"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-06-02T21:15:00Z",
    "severity": "MODERATE"
  },
  "details": "IBM Jazz Foundation and IBM Engineering products are vulnerable to server-side request forgery (SSRF). This may allow an authenticated attacker to send unauthorized requests from the system, potentially leading to network enumeration or facilitating other attacks. IBM X-Force ID: 194596.",
  "id": "GHSA-pf5r-4cpx-xcxm",
  "modified": "2022-05-24T19:03:50Z",
  "published": "2022-05-24T19:03:50Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-20347"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/194596"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/6457739"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-PF6P-25R2-FX45

Vulnerability from github – Published: 2022-06-29 00:00 – Updated: 2022-08-12 21:03
VLAI
Summary
Server-Side Request Forgery in dompdf/dompdf
Details

Server-Side Request Forgery (SSRF) in GitHub repository dompdf/dompdf prior to 2.0.0.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "dompdf/dompdf"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.0.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-0085"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-07-05T22:12:46Z",
    "nvd_published_at": "2022-06-28T15:15:00Z",
    "severity": "MODERATE"
  },
  "details": "Server-Side Request Forgery (SSRF) in GitHub repository dompdf/dompdf prior to 2.0.0.",
  "id": "GHSA-pf6p-25r2-fx45",
  "modified": "2022-08-12T21:03:44Z",
  "published": "2022-06-29T00:00:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-0085"
    },
    {
      "type": "WEB",
      "url": "https://github.com/dompdf/dompdf/commit/bb1ef65011a14730b7cfbe73506b4bb8a03704bd"
    },
    {
      "type": "WEB",
      "url": "https://github.com/FriendsOfPHP/security-advisories/blob/master/dompdf/dompdf/CVE-2022-0085.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/dompdf/dompdf"
    },
    {
      "type": "WEB",
      "url": "https://huntr.dev/bounties/73dbcc78-5ba9-492f-9133-13bbc9f31236"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Server-Side Request Forgery in dompdf/dompdf"
}

No mitigation information available for this CWE.

CAPEC-664: Server Side Request Forgery

An adversary exploits improper input validation by submitting maliciously crafted input to a target application running on a server, with the goal of forcing the server to make a request either to itself, to web services running in the server’s internal network, or to external third parties. If successful, the adversary’s request will be made with the server’s privilege level, bypassing its authentication controls. This ultimately allows the adversary to access sensitive data, execute commands on the server’s network, and make external requests with the stolen identity of the server. Server Side Request Forgery attacks differ from Cross Site Request Forgery attacks in that they target the server itself, whereas CSRF attacks exploit an insecure user authentication mechanism to perform unauthorized actions on the user's behalf.