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.
6158 vulnerabilities reference this CWE, most recent first.
GHSA-X7F7-7836-W8H5
Vulnerability from github – Published: 2026-03-28 06:30 – Updated: 2026-03-28 06:30The Oxygen Theme theme for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 6.0.8 via the laborator_calc_route AJAX action. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.
{
"affected": [],
"aliases": [
"CVE-2025-12886"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-28T04:16:49Z",
"severity": "HIGH"
},
"details": "The Oxygen Theme theme for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 6.0.8 via the laborator_calc_route AJAX action. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.",
"id": "GHSA-x7f7-7836-w8h5",
"modified": "2026-03-28T06:30:24Z",
"published": "2026-03-28T06:30:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-12886"
},
{
"type": "WEB",
"url": "https://documentation.laborator.co/kb/oxygen/oxygen-release-notes"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/8c83f430-8a4d-40fa-890c-387c787a3b55?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-X7HV-CMR9-4HMV
Vulnerability from github – Published: 2025-06-20 15:30 – Updated: 2026-04-01 18:35Server-Side Request Forgery (SSRF) vulnerability in Ali Irani Auto Upload Images allows Server Side Request Forgery. This issue affects Auto Upload Images: from n/a through 3.3.2.
{
"affected": [],
"aliases": [
"CVE-2025-49985"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-06-20T15:15:24Z",
"severity": "MODERATE"
},
"details": "Server-Side Request Forgery (SSRF) vulnerability in Ali Irani Auto Upload Images allows Server Side Request Forgery. This issue affects Auto Upload Images: from n/a through 3.3.2.",
"id": "GHSA-x7hv-cmr9-4hmv",
"modified": "2026-04-01T18:35:31Z",
"published": "2025-06-20T15:30:39Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-49985"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/wordpress/plugin/auto-upload-images/vulnerability/wordpress-auto-upload-images-plugin-3-3-2-server-side-request-forgery-ssrf-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-X7VQ-M9H7-J2WV
Vulnerability from github – Published: 2026-08-31 15:34 – Updated: 2026-08-31 15:34A vulnerability was detected in NASA earthdata-search 1.0.0. Affected by this vulnerability is the function scaleImage of the file serverless/src/scaleImage/handler.js of the component scale Endpoint. Performing a manipulation results in server-side request forgery. The attack can be initiated remotely. The exploit is now public and may be used. The vendor was contacted early about this disclosure but did not respond in any way.
{
"affected": [],
"aliases": [
"CVE-2026-82801"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-31T15:18:19Z",
"severity": "MODERATE"
},
"details": "A vulnerability was detected in NASA earthdata-search 1.0.0. Affected by this vulnerability is the function scaleImage of the file serverless/src/scaleImage/handler.js of the component scale Endpoint. Performing a manipulation results in server-side request forgery. The attack can be initiated remotely. The exploit is now public and may be used. The vendor was contacted early about this disclosure but did not respond in any way.",
"id": "GHSA-x7vq-m9h7-j2wv",
"modified": "2026-08-31T15:34:47Z",
"published": "2026-08-31T15:34:47Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-82801"
},
{
"type": "WEB",
"url": "https://github.com/natanmorette-thoropass/thoropass-vuln-research-program/tree/main/2026/Unauthenticated%20Scale%20Image%20SSRF"
},
{
"type": "WEB",
"url": "https://vuldb.com/cve/CVE-2026-82801"
},
{
"type": "WEB",
"url": "https://vuldb.com/submit/881731"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/397222"
},
{
"type": "WEB",
"url": "https://vuldb.com/vuln/397222/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-X7WF-5MJC-6X76
Vulnerability from github – Published: 2021-04-07 21:13 – Updated: 2024-10-15 20:03Plone before 5.2.3 allows SSRF attacks via the tracebacks feature (only available to the Manager role).
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "Plone"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.2.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "plone.app.event"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.2.10"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "plone.app.theming"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "plone.app.dexterity"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.6.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "plone.supermodel"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.6.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2020-28735"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2021-04-07T19:31:51Z",
"nvd_published_at": "2020-12-30T19:15:00Z",
"severity": "HIGH"
},
"details": "Plone before 5.2.3 allows SSRF attacks via the tracebacks feature (only available to the Manager role).",
"id": "GHSA-x7wf-5mjc-6x76",
"modified": "2024-10-15T20:03:06Z",
"published": "2021-04-07T21:13:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-28735"
},
{
"type": "WEB",
"url": "https://github.com/plone/Products.CMFPlone/issues/3209"
},
{
"type": "WEB",
"url": "https://dist.plone.org/release/5.2.3/RELEASE-NOTES.txt"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-x7wf-5mjc-6x76"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/plone/PYSEC-2020-247.yaml"
},
{
"type": "WEB",
"url": "https://www.misakikata.com/codes/plone/python-en.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "SSRF attacks via tracebacks in Plone"
}
GHSA-X832-R2RJ-4G5P
Vulnerability from github – Published: 2022-02-20 00:00 – Updated: 2023-07-11 00:15An issue was discovered in the Kitodo.Presentation (aka dlf) extension before 2.3.2, 3.x before 3.2.3, and 3.3.x before 3.3.4 for TYPO3. A missing access check in an eID script allows an unauthenticated user to submit arbitrary URLs to this component. This results in SSRF, allowing attackers to view the content of any file or webpage the webserver has access to.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "kitodo/presentation"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.3.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "kitodo/presentation"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.2.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "kitodo/presentation"
},
"ranges": [
{
"events": [
{
"introduced": "3.3.0"
},
{
"fixed": "3.3.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2022-24980"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2023-07-11T00:15:22Z",
"nvd_published_at": "2022-02-19T04:15:00Z",
"severity": "HIGH"
},
"details": "An issue was discovered in the Kitodo.Presentation (aka dlf) extension before 2.3.2, 3.x before 3.2.3, and 3.3.x before 3.3.4 for TYPO3. A missing access check in an eID script allows an unauthenticated user to submit arbitrary URLs to this component. This results in SSRF, allowing attackers to view the content of any file or webpage the webserver has access to.",
"id": "GHSA-x832-r2rj-4g5p",
"modified": "2023-07-11T00:15:22Z",
"published": "2022-02-20T00:00:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-24980"
},
{
"type": "WEB",
"url": "https://github.com/kitodo/kitodo-presentation/commit/059be3f82b08c60cbb798986cd3ff22dbf60a5e4"
},
{
"type": "WEB",
"url": "https://github.com/kitodo/kitodo-presentation/commit/4a20621afc30778ba3b045be5110353cf4fd4fd4"
},
{
"type": "WEB",
"url": "https://github.com/kitodo/kitodo-presentation/commit/9700478b46445f562c3e2051d61565d779f59275"
},
{
"type": "WEB",
"url": "https://security.snyk.io/vuln/SNYK-PHP-KITODOPRESENTATION-2407280"
},
{
"type": "WEB",
"url": "https://typo3.org/help/security-advisories"
},
{
"type": "WEB",
"url": "https://typo3.org/security/advisory/typo3-ext-sa-2022-001"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "SSRF in Kitodo.Presentation"
}
GHSA-X87C-G7PW-2XR5
Vulnerability from github – Published: 2026-04-10 21:31 – Updated: 2026-04-16 03:31GeoNode versions 4.0 before 4.4.5 and 5.0 before 5.0.2 contain a server-side request forgery vulnerability that allows authenticated users with document upload permissions to trigger arbitrary outbound HTTP requests by providing a malicious URL via the doc_url parameter during document upload. Attackers can supply URLs pointing to internal network targets, loopback addresses, RFC1918 addresses, or cloud metadata services to cause the server to make requests to internal resources without SSRF mitigations such as private IP filtering or redirect validation.
{
"affected": [],
"aliases": [
"CVE-2026-39921"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-10T20:16:22Z",
"severity": "MODERATE"
},
"details": "GeoNode versions 4.0 before 4.4.5 and 5.0 before 5.0.2 contain a server-side request forgery vulnerability that allows authenticated users with document upload permissions to trigger arbitrary outbound HTTP requests by providing a malicious URL via the doc_url parameter during document upload. Attackers can supply URLs pointing to internal network targets, loopback addresses, RFC1918 addresses, or cloud metadata services to cause the server to make requests to internal resources without SSRF mitigations such as private IP filtering or redirect validation.",
"id": "GHSA-x87c-g7pw-2xr5",
"modified": "2026-04-16T03:31:05Z",
"published": "2026-04-10T21:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-39921"
},
{
"type": "WEB",
"url": "https://github.com/GeoNode/geonode/pull/14058"
},
{
"type": "WEB",
"url": "https://github.com/GeoNode/geonode/commit/4a852cfc1da732b10779b5bf5f087c8f02985571"
},
{
"type": "WEB",
"url": "https://github.com/GeoNode/geonode/commit/9856cb5ab27e33c0adba9274f4cccf6d1f534bd1"
},
{
"type": "WEB",
"url": "https://github.com/GeoNode/geonode/releases/tag/4.4.5"
},
{
"type": "WEB",
"url": "https://github.com/GeoNode/geonode/releases/tag/5.0.2"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/geonode-ssrf-via-document-upload"
}
],
"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:N/SC:L/SI:L/SA:L/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-X8F4-GHF2-WCMP
Vulnerability from github – Published: 2026-10-01 12:31 – Updated: 2026-10-01 12:31Ghost versions from 3.20.2 before 6.51.0 contain a server-side request forgery vulnerability in image dimension refetching that allows authenticated staff users to trigger outbound HTTP requests to arbitrary URLs. Attackers can point image cards at attacker-controlled hosts or internal network endpoints to access metadata services and internal resources unavailable from the public internet.
{
"affected": [],
"aliases": [
"CVE-2026-103291"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-10-01T11:17:25Z",
"severity": "MODERATE"
},
"details": "Ghost versions from 3.20.2 before 6.51.0 contain a server-side request forgery vulnerability in image dimension refetching that allows authenticated staff users to trigger outbound HTTP requests to arbitrary URLs. Attackers can point image cards at attacker-controlled hosts or internal network endpoints to access metadata services and internal resources unavailable from the public internet.",
"id": "GHSA-x8f4-ghf2-wcmp",
"modified": "2026-10-01T12:31:19Z",
"published": "2026-10-01T12:31:19Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/TryGhost/Ghost/security/advisories/GHSA-rrq6-9r3c-7w26"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-103291"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/ghost-3.20.2-before-6.51.0-ssrf-via-image-size-fetch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/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-X8G9-H984-PC36
Vulnerability from github – Published: 2026-06-26 22:11 – Updated: 2026-06-26 22:11Summary
pontedilana/php-weasyprint fetches the content of option values server-side via file_get_contents() when the value looks like a URL, without restricting the URL scheme. The attachment option of Pdf is the reachable sink: any value that passes isOptionUrl() (filter_var(..., FILTER_VALIDATE_URL)) is downloaded by the PHP process and embedded into the generated PDF. Because FILTER_VALIDATE_URL accepts http, https, ftp, file and PHP stream wrappers such as php://, an attacker who can influence the attachment value reaches both a Server-Side Request Forgery primitive (e.g. internal HTTP endpoints, cloud metadata) and a local file disclosure primitive (file://, php://filter/...), with the fetched bytes exfiltrated as a PDF attachment.
This is the same class of issue KnpLabs/snappy patched for its xsl-style-sheet option in GHSA-c5fp-p67m-gq56. The library is documented as a one-to-one substitute for KnpLabs/snappy and shares the same code shape.
Affected versions
pontedilana/php-weasyprint versions <= 2.5.1.
Patched in: 2.6.0.
Privilege required
Any caller that can influence the attachment option value handed to Pdf::generate() / Pdf::getOutput() / setOption('attachment', ...). Typical reach paths: a value sourced from a request parameter, a per-tenant configuration row, or any user-controllable field that flows into the attachment list.
Vulnerable code
src/Pdf.php — isOptionUrl() accepts any well-formed URL regardless of scheme:
protected function isOptionUrl($option): bool
{
return false !== \filter_var($option, \FILTER_VALIDATE_URL);
}
src/Pdf.php — handleArrayOptions() fetches the URL content for the attachment option:
$fetchUrlContent = 'attachment' === $option && $this->isOptionUrl($item);
if ($saveToTempFile || $fetchUrlContent) {
$fileContent = $fetchUrlContent ? \file_get_contents($item) : $item;
$returnOptions[] = $this->createTemporaryFile($fileContent, $this->optionsWithContentCheck[$option] ?? 'temp');
}
FILTER_VALIDATE_URL returns truthy for http://, https://, ftp://, file://localhost/..., and php://filter/..., so \file_get_contents() is invoked on attacker-chosen schemes with no allow-list.
Proof of concept
<?php
use Pontedilana\PhpWeasyPrint\Pdf;
$pdf = new Pdf('/usr/local/bin/weasyprint');
// Attacker-controlled attachment value (e.g. from a request / tenant config):
// SSRF: http://169.254.169.254/latest/meta-data/iam/security-credentials/
// Local file read: php://filter/convert.base64-encode/resource=/etc/passwd
$attachment = $_GET['doc'];
$pdf->generate('page.html', 'out.pdf', [
'attachment' => $attachment,
]);
// The bytes fetched server-side by file_get_contents() are embedded in out.pdf,
// allowing the attacker to read internal HTTP responses or local files.
Impact
- SSRF: the server fetches arbitrary
http(s)/ftpURLs, reaching internal-only services, link-local metadata endpoints, etc. - Local file / wrapper disclosure:
php://filter/...(and similar) let an attacker read and exfiltrate local file content inside the generated PDF. - Affects any consumer that does not fully control the
attachmentoption value.
Note: passing a plain local path (e.g. /etc/passwd) or a file:// path that resolves to an existing file is handled as a normal local attachment and is not the issue addressed here — that is the documented local-attachment feature (callers must not pass untrusted input to the option). The fix specifically removes the server-side fetch amplification through non-http(s) schemes.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (6.5, Medium) — adjust PR/S/A to the consuming application's reachability (e.g. PR:N if the attachment value is reachable from an unauthenticated surface).
CWE-918 (Server-Side Request Forgery); secondary CWE-22 (Improper Limitation of a Pathname) for the wrapper-based file read.
Suggested fix
Restrict the schemes the library will fetch to an allow-list (http, https by default), and treat any other scheme as inline content instead of fetching it:
private array $allowedSchemes = ['http', 'https'];
// new optional 4th constructor argument: ?array $allowedSchemes = null
protected function isOptionUrl($option): bool
{
$url = \parse_url((string)$option);
return false !== $url
&& isset($url['scheme'])
&& \in_array(\strtolower($url['scheme']), $this->allowedSchemes, true);
}
A value with a non-allowed scheme (file://, php://, ftp://, ...) is then never passed to file_get_contents().
Credit
Reported upstream to KnpLabs/snappy (GHSA-c5fp-p67m-gq56); identified as applicable to pontedilana/php-weasyprint, which mirrors the same code.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.5.1"
},
"package": {
"ecosystem": "Packagist",
"name": "pontedilana/php-weasyprint"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-49359"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-26T22:11:40Z",
"nvd_published_at": "2026-06-19T18:16:19Z",
"severity": "MODERATE"
},
"details": "### Summary\n\n`pontedilana/php-weasyprint` fetches the content of option values server-side via `file_get_contents()` when the value looks like a URL, without restricting the URL scheme. The `attachment` option of `Pdf` is the reachable sink: any value that passes `isOptionUrl()` (`filter_var(..., FILTER_VALIDATE_URL)`) is downloaded by the PHP process and embedded into the generated PDF. Because `FILTER_VALIDATE_URL` accepts `http`, `https`, `ftp`, `file` and PHP stream wrappers such as `php://`, an attacker who can influence the `attachment` value reaches both a **Server-Side Request Forgery** primitive (e.g. internal HTTP endpoints, cloud metadata) and a **local file disclosure** primitive (`file://`, `php://filter/...`), with the fetched bytes exfiltrated as a PDF attachment.\n\nThis is the same class of issue KnpLabs/snappy patched for its `xsl-style-sheet` option in [GHSA-c5fp-p67m-gq56](https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56). The library is documented as a one-to-one substitute for KnpLabs/snappy and shares the same code shape.\n\n### Affected versions\n\n`pontedilana/php-weasyprint` versions `\u003c= 2.5.1`.\n\nPatched in: `2.6.0`.\n\n### Privilege required\n\nAny caller that can influence the `attachment` option value handed to `Pdf::generate()` / `Pdf::getOutput()` / `setOption(\u0027attachment\u0027, ...)`. Typical reach paths: a value sourced from a request parameter, a per-tenant configuration row, or any user-controllable field that flows into the attachment list.\n\n### Vulnerable code\n\n`src/Pdf.php` \u2014 `isOptionUrl()` accepts any well-formed URL regardless of scheme:\n\n```php\nprotected function isOptionUrl($option): bool\n{\n return false !== \\filter_var($option, \\FILTER_VALIDATE_URL);\n}\n```\n\n`src/Pdf.php` \u2014 `handleArrayOptions()` fetches the URL content for the `attachment` option:\n\n```php\n$fetchUrlContent = \u0027attachment\u0027 === $option \u0026\u0026 $this-\u003eisOptionUrl($item);\nif ($saveToTempFile || $fetchUrlContent) {\n $fileContent = $fetchUrlContent ? \\file_get_contents($item) : $item;\n $returnOptions[] = $this-\u003ecreateTemporaryFile($fileContent, $this-\u003eoptionsWithContentCheck[$option] ?? \u0027temp\u0027);\n}\n```\n\n`FILTER_VALIDATE_URL` returns truthy for `http://`, `https://`, `ftp://`, `file://localhost/...`, and `php://filter/...`, so `\\file_get_contents()` is invoked on attacker-chosen schemes with no allow-list.\n\n### Proof of concept\n\n```php\n\u003c?php\nuse Pontedilana\\PhpWeasyPrint\\Pdf;\n\n$pdf = new Pdf(\u0027/usr/local/bin/weasyprint\u0027);\n\n// Attacker-controlled attachment value (e.g. from a request / tenant config):\n// SSRF: http://169.254.169.254/latest/meta-data/iam/security-credentials/\n// Local file read: php://filter/convert.base64-encode/resource=/etc/passwd\n$attachment = $_GET[\u0027doc\u0027];\n\n$pdf-\u003egenerate(\u0027page.html\u0027, \u0027out.pdf\u0027, [\n \u0027attachment\u0027 =\u003e $attachment,\n]);\n\n// The bytes fetched server-side by file_get_contents() are embedded in out.pdf,\n// allowing the attacker to read internal HTTP responses or local files.\n```\n\n### Impact\n\n- **SSRF**: the server fetches arbitrary `http(s)`/`ftp` URLs, reaching internal-only services, link-local metadata endpoints, etc.\n- **Local file / wrapper disclosure**: `php://filter/...` (and similar) let an attacker read and exfiltrate local file content inside the generated PDF.\n- Affects any consumer that does not fully control the `attachment` option value.\n\nNote: passing a plain local path (e.g. `/etc/passwd`) or a `file://` path that resolves to an existing file is handled as a normal local attachment and is **not** the issue addressed here \u2014 that is the documented local-attachment feature (callers must not pass untrusted input to the option). The fix specifically removes the server-side fetch amplification through non-`http(s)` schemes.\n\nCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (6.5, Medium) \u2014 adjust `PR`/`S`/`A` to the consuming application\u0027s reachability (e.g. `PR:N` if the attachment value is reachable from an unauthenticated surface).\n\nCWE-918 (Server-Side Request Forgery); secondary CWE-22 (Improper Limitation of a Pathname) for the wrapper-based file read.\n\n### Suggested fix\n\nRestrict the schemes the library will fetch to an allow-list (`http`, `https` by default), and treat any other scheme as inline content instead of fetching it:\n\n```php\nprivate array $allowedSchemes = [\u0027http\u0027, \u0027https\u0027];\n\n// new optional 4th constructor argument: ?array $allowedSchemes = null\n\nprotected function isOptionUrl($option): bool\n{\n $url = \\parse_url((string)$option);\n\n return false !== $url\n \u0026\u0026 isset($url[\u0027scheme\u0027])\n \u0026\u0026 \\in_array(\\strtolower($url[\u0027scheme\u0027]), $this-\u003eallowedSchemes, true);\n}\n```\n\nA value with a non-allowed scheme (`file://`, `php://`, `ftp://`, ...) is then never passed to `file_get_contents()`.\n\n### Credit\n\nReported upstream to KnpLabs/snappy ([GHSA-c5fp-p67m-gq56](https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56)); identified as applicable to `pontedilana/php-weasyprint`, which mirrors the same code.",
"id": "GHSA-x8g9-h984-pc36",
"modified": "2026-06-26T22:11:40Z",
"published": "2026-06-26T22:11:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56"
},
{
"type": "WEB",
"url": "https://github.com/pontedilana/php-weasyprint/security/advisories/GHSA-x8g9-h984-pc36"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-49359"
},
{
"type": "WEB",
"url": "https://github.com/pontedilana/php-weasyprint/commit/9582dcf119a405276cf55e9e10bc577a887792cb"
},
{
"type": "PACKAGE",
"url": "https://github.com/pontedilana/php-weasyprint"
},
{
"type": "WEB",
"url": "https://github.com/pontedilana/php-weasyprint/releases/tag/2.6.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "PhpWeasyPrint vulnerable to SSRF and local file disclosure via the attachment option"
}
GHSA-X8GV-G2G3-65FJ
Vulnerability from github – Published: 2026-10-02 23:17 – Updated: 2026-10-02 23:17Security Advisory — SiYuan Agent Tools SSRF via DNS-Rebinding TOCTOU (Bypass of CheckHostSSRF)
| Field | Value |
|---|---|
| Disclosed by | joysinleung (joysinleung@gmail.com) |
| Report date | 2026-08-13 |
| Product | SiYuan (思源笔记) — siyuan-note/siyuan |
| Go module | github.com/siyuan-note/siyuan/kernel |
| Affected versions | <= 3.8.0 (latest release at report time; dynamically verified on v3.8.0) |
| Patched versions | 3.8.1 |
| Component | kernel/util/httprequest.go (CheckHostSSRF), kernel/mcp/tools/http_request.go, kernel/util/webfetch.go, kernel/util/net.go (SSRFSafeDialer) |
| Relationship to prior advisory | Incomplete-fix variant of GHSA-rg26-cg95-gq6p (SSRF main-vector remediation). See §Relationship. |
| EPSS (exploitation probability) | Low–Moderate. Requires the attacker to influence an AI Agent / MCP client into fetching an attacker-controlled domain (prompt-injection scenario documented by the tool itself). |
| KEV (CISA Known Exploited) | No (not listed in CISA KEV at report time). |
| Default-config reachable | Yes — exploitable under both SafeMode on and off; only requires the agent http_request / web_fetch tool to be reachable (default AI tooling). |
Summary
SiYuan's AI Agent tools http_request (util.HTTPRequest) and web_fetch (util.WebFetch) are the only SSRF gate for outbound requests from the kernel. That gate is CheckHostSSRF, which performs a single DNS resolution at guard time and checks whether any returned IP is private/loopback/link-local. The actual connection, however, performs a second, independent DNS resolution through the default net.Dialer — and no connect-time private-IP check is mounted on this path.
Because the two resolutions are not pinned to the same result, an attacker-controlled domain can answer the guard-resolution with a public IP (passing CheckHostSSRF) and the connect-resolution with a private/loopback/metadata IP (e.g. 169.254.169.254). This is a classic DNS-rebinding TOCTOU that bypasses the SSRF defense entirely. It reaches cloud instance metadata and internal services that the guard was specifically added to block.
Relationship to Prior Advisories
- GHSA-rg26-cg95-gq6p remediated the SSRF main vector by adding
CheckHostSSRF(parse-time) andSSRFSafeDialer(connect-time). However, the agent tool paths (http_request/web_fetch) only received the parse-time half: they callCheckHostSSRFbut then connect viahttpclient.NewBrowserRequest(), whose transport does not mountSSRFSafeDialer. Even whereSSRFSafeDialeris mounted, it only blocks private IPs whenSafeMode == true(default false), so it would not help here regardless. The sibling pathopenai.go:generatedImageDialerdoes mount a connect-timeControlhook (blocking private/loopback/link-local/100.64/198.18), proving the project knows the technique — the agent path is a clear omission. We report this as an incomplete-fix variant with a concrete v3.8.0 reproduction. - CVE-2026-32110 (GHSA-56cv-c5p2-j2wg) covered the older
forwardProxyendpoint and is unrelated to the agent tool path.
Affected Version
Dynamically verified on v3.8.0 (tag v3.8.0, commit 251596fc0). A process-level DNS hijack was installed so that the attacker domain rebind.local returns a public IP (203.0.113.1) on odd (guard) resolutions and 127.0.0.1 on even (connect) resolutions; a loopback "victim" service returned F9_REBIND_PROOF=reached-internal-only-service-via-TOCTOU. Both util.HTTPRequest("GET", "http://rebind.local:<port>/secret") and util.WebFetch(...) returned the internal-only proof body, while CheckHostSSRF("127.0.0.1") directly blocked and the legit public domain pub.local passed — confirming the guard passed but the connection hit the internal address. All versions <= 3.8.0 are affected.
Component
kernel/util/httprequest.go:42CheckHostSSRF— singlenet.LookupIP+isPrivateIPat guard time only.kernel/mcp/tools/http_request.go:90→util.HTTPRequest;kernel/util/webfetch.go:50→CheckHostSSRF+httpclient.NewBrowserRequest().github.com/siyuan-note/httpclientclient.go:92NewBrowserRequestuses the defaulthttp.Transport→ defaultnet.Dialerwith noSSRFSafeDialer.kernel/util/net.go:151SSRFSafeDialerexists but is (a) not mounted on the agent path and (b) only active underSafeMode.- Correctly-defended sibling:
kernel/util/openai.go:829generatedImageDialermounts a connect-timeControlhook.
Attack Vector
Network + AI Agent. The url of http_request / web_fetch is fully controlled by the agent / MCP client. In SiYuan's documented red-team scenario ("prompt-inject the agent → induce it to visit an attacker domain"), the attacker needs only a rebinding domain (own authoritative DNS, first answer public, later 169.254.169.254 / internal). No auth, no special position beyond prompting the agent. Real targets: cloud metadata 169.254.169.254 (IMDSv1 IAM creds) and same-host/internal unauthenticated services.
Proof of Concept
# Attacker authoritative DNS for rebind.local:
# odd query (guard) -> 203.0.113.1 (public, passes CheckHostSSRF)
# even query (dial) -> 127.0.0.1 (loopback internal victim)
#
# Directly invoke the real agent-tool functions (v3.8.0 code path):
util.HTTPRequest("GET", "http://rebind.local:15353/secret", ...)
util.WebFetch("http://rebind.local:15353/secret", ...)
# Result (evidence):
# body = "F9_REBIND_PROOF=reached-internal-only-service-via-TOCTOU"
# Negative control: CheckHostSSRF("127.0.0.1") -> blocked.
# Positive control: CheckHostSSRF("pub.local") -> 203.0.113.1, allowed.
The loopback victim is a faithful stand-in for 169.254.169.254 / any internal address: the guard allowed a public IP while the connection reached a private one.
Impact
Confidentiality breach via SSRF: an attacker who can steer the agent can read cloud instance metadata (IAM temporary credentials), internal service responses, and anything reachable from the SiYuan kernel's network position. Scope is changed (S:C) because the kernel often runs with cloud-instance privileges. Exploitable under default config (SafeMode on or off).
Scope
Reachable whenever the agent http_request / web_fetch tool is usable (default AI tooling). Independent of Publish/auth configuration. Not gated by SafeMode.
Remediation
- Connect-time enforcement (preferred): mount
SSRFSafeDialer(or a dedicated always-on private-IPControlhook) on the transport used byhttp_request/web_fetch, independent ofSafeMode— matching the already-correctgeneratedImageDialer. - Pin resolution: after
CheckHostSSRFpasses, reuse the same resolved IP for the connection (or short-TTL cache) so guard and dial cannot diverge. - Minimum change: replace
httpclient.NewBrowserRequest()inhttp_request.go/webfetch.gowith a custom client whoseDialContextisutil.SSRFSafeDialer(timeout).DialContext(notSafeMode-gated).
Note: patch authored against v3.8.0 source; regression-tested in the researcher's environment for the PoC path but not compiled into a full SiYuan release build. Provided for the maintainer to validate in CI.
Appendix: Suggested Patch (F9)
diff --git a/kernel/util/httprequest.go b/kernel/util/httprequest.go
index aaa..bbb 100644
--- a/kernel/util/httprequest.go
+++ b/kernel/util/httprequest.go
@@ -40,6 +40,18 @@ func CheckHostSSRF(host string) error {
return nil
}
+// SSRFSafeClient returns an *http.Client whose transport enforces the
+// private/loopback/link-local IP block at CONNECT time (independent of SafeMode),
+// closing the DNS-rebinding TOCTOU left by parse-time-only CheckHostSSRF.
+func SSRFSafeClient(timeout time.Duration) *http.Client {
+ return &http.Client{
+ Timeout: timeout,
+ Transport: &http.Transport{
+ DialContext: util.SSRFSafeDialer(timeout).DialContext,
+ },
+ }
+}
+
diff --git a/kernel/mcp/tools/http_request.go b/kernel/mcp/tools/http_request.go
index ccc..ddd 100644
--- a/kernel/mcp/tools/http_request.go
+++ b/kernel/mcp/tools/http_request.go
@@ -90,7 +90,7 @@ func httpRequest(args map[string]any) (CallToolResult, error) {
if serr := util.CheckHostSSRF(u.Hostname()); serr != nil {
return CallToolResult{}, serr
}
- resp, err := httpclient.NewBrowserRequest().Get(rawURL)
+ resp, err := util.SSRFSafeClient(30 * time.Second).Get(rawURL)
...
}
diff --git a/kernel/util/webfetch.go b/kernel/util/webfetch.go
index eee..fff 100644
--- a/kernel/util/webfetch.go
+++ b/kernel/util/webfetch.go
@@ -50,7 +50,7 @@ func WebFetch(rawURL string, ...) (string, error) {
if serr := util.CheckHostSSRF(u.Hostname()); serr != nil {
return "", serr
}
- resp, err := httpclient.NewBrowserRequest().Get(rawURL)
+ resp, err := util.SSRFSafeClient(30 * time.Second).Get(rawURL)
...
}
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/siyuan-note/siyuan/kernel"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.0.0-20260813142806-dd2778b70d02"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-02T23:17:16Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "# Security Advisory \u2014 SiYuan Agent Tools SSRF via DNS-Rebinding TOCTOU (Bypass of `CheckHostSSRF`)\n\n| Field | Value |\n|---|---|\n| **Disclosed by** | joysinleung (`joysinleung@gmail.com`) |\n| **Report date** | 2026-08-13 |\n| **Product** | SiYuan (\u601d\u6e90\u7b14\u8bb0) \u2014 `siyuan-note/siyuan` |\n| **Go module** | `github.com/siyuan-note/siyuan/kernel` |\n| **Affected versions** | `\u003c= 3.8.0` (latest release at report time; dynamically verified on v3.8.0) |\n| **Patched versions** | 3.8.1 |\n| **Component** | `kernel/util/httprequest.go` (`CheckHostSSRF`), `kernel/mcp/tools/http_request.go`, `kernel/util/webfetch.go`, `kernel/util/net.go` (`SSRFSafeDialer`) |\n| **Relationship to prior advisory** | **Incomplete-fix variant of GHSA-rg26-cg95-gq6p** (SSRF main-vector remediation). See \u00a7Relationship. |\n| **EPSS (exploitation probability)** | Low\u2013Moderate. Requires the attacker to influence an AI Agent / MCP client into fetching an attacker-controlled domain (prompt-injection scenario documented by the tool itself). |\n| **KEV (CISA Known Exploited)** | No (not listed in CISA KEV at report time). |\n| **Default-config reachable** | **Yes** \u2014 exploitable under *both* `SafeMode` on and off; only requires the agent `http_request` / `web_fetch` tool to be reachable (default AI tooling). |\n\n---\n\n## Summary\n\nSiYuan\u0027s AI Agent tools `http_request` (`util.HTTPRequest`) and `web_fetch` (`util.WebFetch`) are the only SSRF gate for outbound requests from the kernel. That gate is `CheckHostSSRF`, which performs a **single DNS resolution at guard time** and checks whether any returned IP is private/loopback/link-local. The actual connection, however, performs a **second, independent DNS resolution** through the default `net.Dialer` \u2014 and **no connect-time private-IP check is mounted** on this path.\n\nBecause the two resolutions are not pinned to the same result, an attacker-controlled domain can answer the guard-resolution with a **public IP** (passing `CheckHostSSRF`) and the connect-resolution with a **private/loopback/metadata IP** (e.g. `169.254.169.254`). This is a classic **DNS-rebinding TOCTOU** that bypasses the SSRF defense entirely. It reaches cloud instance metadata and internal services that the guard was specifically added to block.\n\n## Relationship to Prior Advisories\n\n- **GHSA-rg26-cg95-gq6p** remediated the SSRF *main vector* by adding `CheckHostSSRF` (parse-time) **and** `SSRFSafeDialer` (connect-time). However, **the agent tool paths (`http_request` / `web_fetch`) only received the parse-time half**: they call `CheckHostSSRF` but then connect via `httpclient.NewBrowserRequest()`, whose transport does **not** mount `SSRFSafeDialer`. Even where `SSRFSafeDialer` *is* mounted, it only blocks private IPs when `SafeMode == true` (default false), so it would not help here regardless. The sibling path `openai.go:generatedImageDialer` *does* mount a connect-time `Control` hook (blocking private/loopback/link-local/100.64/198.18), proving the project knows the technique \u2014 the agent path is a clear omission. We report this as an **incomplete-fix variant** with a concrete v3.8.0 reproduction.\n- **CVE-2026-32110** (GHSA-56cv-c5p2-j2wg) covered the older `forwardProxy` endpoint and is unrelated to the agent tool path.\n\n## Affected Version\n\n**Dynamically verified on v3.8.0** (tag `v3.8.0`, commit `251596fc0`). A process-level DNS hijack was installed so that the attacker domain `rebind.local` returns a public IP (`203.0.113.1`) on odd (guard) resolutions and `127.0.0.1` on even (connect) resolutions; a loopback \"victim\" service returned `F9_REBIND_PROOF=reached-internal-only-service-via-TOCTOU`. Both `util.HTTPRequest(\"GET\", \"http://rebind.local:\u003cport\u003e/secret\")` and `util.WebFetch(...)` returned the internal-only proof body, while `CheckHostSSRF(\"127.0.0.1\")` directly blocked and the legit public domain `pub.local` passed \u2014 confirming the guard passed but the connection hit the internal address. All versions `\u003c= 3.8.0` are affected.\n\n## Component\n\n- `kernel/util/httprequest.go:42` `CheckHostSSRF` \u2014 single `net.LookupIP` + `isPrivateIP` at guard time only.\n- `kernel/mcp/tools/http_request.go:90` \u2192 `util.HTTPRequest`; `kernel/util/webfetch.go:50` \u2192 `CheckHostSSRF` + `httpclient.NewBrowserRequest()`.\n- `github.com/siyuan-note/httpclient` `client.go:92` `NewBrowserRequest` uses the default `http.Transport` \u2192 default `net.Dialer` with **no `SSRFSafeDialer`**.\n- `kernel/util/net.go:151` `SSRFSafeDialer` exists but is (a) not mounted on the agent path and (b) only active under `SafeMode`.\n- Correctly-defended sibling: `kernel/util/openai.go:829` `generatedImageDialer` mounts a connect-time `Control` hook.\n\n\n## Attack Vector\n\n**Network + AI Agent.** The `url` of `http_request` / `web_fetch` is fully controlled by the agent / MCP client. In SiYuan\u0027s documented red-team scenario (\"prompt-inject the agent \u2192 induce it to visit an attacker domain\"), the attacker needs only a rebinding domain (own authoritative DNS, first answer public, later `169.254.169.254` / internal). No auth, no special position beyond prompting the agent. Real targets: cloud metadata `169.254.169.254` (IMDSv1 IAM creds) and same-host/internal unauthenticated services.\n\n## Proof of Concept\n\n```\n# Attacker authoritative DNS for rebind.local:\n# odd query (guard) -\u003e 203.0.113.1 (public, passes CheckHostSSRF)\n# even query (dial) -\u003e 127.0.0.1 (loopback internal victim)\n#\n# Directly invoke the real agent-tool functions (v3.8.0 code path):\nutil.HTTPRequest(\"GET\", \"http://rebind.local:15353/secret\", ...)\nutil.WebFetch(\"http://rebind.local:15353/secret\", ...)\n\n# Result (evidence):\n# body = \"F9_REBIND_PROOF=reached-internal-only-service-via-TOCTOU\"\n# Negative control: CheckHostSSRF(\"127.0.0.1\") -\u003e blocked.\n# Positive control: CheckHostSSRF(\"pub.local\") -\u003e 203.0.113.1, allowed.\n```\n\nThe loopback victim is a faithful stand-in for `169.254.169.254` / any internal address: the guard allowed a public IP while the connection reached a private one.\n\n## Impact\n\nConfidentiality breach via SSRF: an attacker who can steer the agent can read cloud instance metadata (IAM temporary credentials), internal service responses, and anything reachable from the SiYuan kernel\u0027s network position. Scope is changed (`S:C`) because the kernel often runs with cloud-instance privileges. Exploitable under default config (SafeMode on or off).\n\n## Scope\n\nReachable whenever the agent `http_request` / `web_fetch` tool is usable (default AI tooling). Independent of Publish/auth configuration. Not gated by `SafeMode`.\n\n## Remediation\n\n1. **Connect-time enforcement (preferred)**: mount `SSRFSafeDialer` (or a dedicated always-on private-IP `Control` hook) on the transport used by `http_request` / `web_fetch`, independent of `SafeMode` \u2014 matching the already-correct `generatedImageDialer`.\n2. **Pin resolution**: after `CheckHostSSRF` passes, reuse the *same* resolved IP for the connection (or short-TTL cache) so guard and dial cannot diverge.\n3. **Minimum change**: replace `httpclient.NewBrowserRequest()` in `http_request.go` / `webfetch.go` with a custom client whose `DialContext` is `util.SSRFSafeDialer(timeout).DialContext` (not `SafeMode`-gated).\n\n\u003e Note: patch authored against v3.8.0 source; regression-tested in the researcher\u0027s environment for the PoC path but not compiled into a full SiYuan release build. Provided for the maintainer to validate in CI.\n\n---\n\n## Appendix: Suggested Patch (F9)\n\n```diff\ndiff --git a/kernel/util/httprequest.go b/kernel/util/httprequest.go\nindex aaa..bbb 100644\n--- a/kernel/util/httprequest.go\n+++ b/kernel/util/httprequest.go\n@@ -40,6 +40,18 @@ func CheckHostSSRF(host string) error {\n \treturn nil\n }\n \n+// SSRFSafeClient returns an *http.Client whose transport enforces the\n+// private/loopback/link-local IP block at CONNECT time (independent of SafeMode),\n+// closing the DNS-rebinding TOCTOU left by parse-time-only CheckHostSSRF.\n+func SSRFSafeClient(timeout time.Duration) *http.Client {\n+\treturn \u0026http.Client{\n+\t\tTimeout: timeout,\n+\t\tTransport: \u0026http.Transport{\n+\t\t\tDialContext: util.SSRFSafeDialer(timeout).DialContext,\n+\t\t},\n+\t}\n+}\n+\n diff --git a/kernel/mcp/tools/http_request.go b/kernel/mcp/tools/http_request.go\n index ccc..ddd 100644\n--- a/kernel/mcp/tools/http_request.go\n+++ b/kernel/mcp/tools/http_request.go\n@@ -90,7 +90,7 @@ func httpRequest(args map[string]any) (CallToolResult, error) {\n \tif serr := util.CheckHostSSRF(u.Hostname()); serr != nil {\n \t\treturn CallToolResult{}, serr\n \t}\n-\tresp, err := httpclient.NewBrowserRequest().Get(rawURL)\n+\tresp, err := util.SSRFSafeClient(30 * time.Second).Get(rawURL)\n \t...\n }\n diff --git a/kernel/util/webfetch.go b/kernel/util/webfetch.go\n index eee..fff 100644\n--- a/kernel/util/webfetch.go\n+++ b/kernel/util/webfetch.go\n@@ -50,7 +50,7 @@ func WebFetch(rawURL string, ...) (string, error) {\n \tif serr := util.CheckHostSSRF(u.Hostname()); serr != nil {\n \t\treturn \"\", serr\n \t}\n-\tresp, err := httpclient.NewBrowserRequest().Get(rawURL)\n+\tresp, err := util.SSRFSafeClient(30 * time.Second).Get(rawURL)\n \t...\n }\n```",
"id": "GHSA-x8gv-g2g3-65fj",
"modified": "2026-10-02T23:17:16Z",
"published": "2026-10-02T23:17:16Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-x8gv-g2g3-65fj"
},
{
"type": "WEB",
"url": "https://github.com/siyuan-note/siyuan/commit/dd2778b70d020b15491ef7418f5f63214583cd63"
},
{
"type": "PACKAGE",
"url": "https://github.com/siyuan-note/siyuan"
},
{
"type": "WEB",
"url": "https://github.com/siyuan-note/siyuan/releases/tag/v3.8.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "SiYuan Agent Tools SSRF via DNS-Rebinding TOCTOU (Bypass of CheckHostSSRF)"
}
GHSA-X8H5-CPR3-H43M
Vulnerability from github – Published: 2026-08-11 12:30 – Updated: 2026-08-11 12:30A server-side request forgery vulnerability in Pinry through 2.1.13 allows unauthenticated remote attackers to make the server issue HTTP requests to arbitrary internal or external hosts via the pin-from-URL feature. The feature passes the user-supplied URL directly to requests.get() without host or IP validation, and ALLOW_NEW_REGISTRATIONS defaults to true enabling anonymous triggering. An attacker can reach internal services or cloud metadata endpoints from the server.
{
"affected": [],
"aliases": [
"CVE-2026-72606"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-11T12:17:43Z",
"severity": "HIGH"
},
"details": "A server-side request forgery vulnerability in Pinry through 2.1.13 allows unauthenticated remote attackers to make the server issue HTTP requests to arbitrary internal or external hosts via the pin-from-URL feature. The feature passes the user-supplied URL directly to requests.get() without host or IP validation, and ALLOW_NEW_REGISTRATIONS defaults to true enabling anonymous triggering. An attacker can reach internal services or cloud metadata endpoints from the server.",
"id": "GHSA-x8h5-cpr3-h43m",
"modified": "2026-08-11T12:30:28Z",
"published": "2026-08-11T12:30:28Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-72606"
},
{
"type": "WEB",
"url": "https://github.com/pinry/pinry"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"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.