GHSA-78x9-fhhx-v2g6
CKAN MCP Server: Cache-key canonicalization collision enables cache confusion / poisoning
Quick fix
GHSA-78x9-fhhx-v2g6 — @aborruso/ckan-mcp-server: upgrade to the fixed version with the command below.
npm install @aborruso/ckan-mcp-server@0.4.112Details
## Summary
The response cache derives its key from an ambiguous string serialization of the request parameters. `canonicalizeParams` joins sorted `${key}=${value}` pairs with `&` and does not escape `&`, `=`, or the `|` field separators used in `buildCacheKey`. Two **different** logical parameter sets can therefore serialize to the **same** key and share one cache entry. Because the cached value is whatever the upstream returned for whichever request populated the entry first, an attacker can prime a colliding key so a victim's distinct query (same `server_url`) is served the attacker's cached response.
## Affected code
```js // src/utils/cache.ts export function canonicalizeParams(params) { const keys = Object.keys(params).sort(); const pairs = []; for (const key of keys) { const value = params[key]; if (value === undefined || value === null) continue; const serialized = typeof value === "object" ? JSON.stringify(value) : String(value); pairs.push(`${key}=${serialized}`); // value not escaped } return pairs.join("&"); // '&' delimiter, injectable }
export async function buildCacheKey(serverUrl, action, params) { const raw = `${serverUrl}|${action}|${canonicalizeParams(params)}`; // '|' also unescaped return sha1Hex(raw); } ```
Confirmed collisions (identical key):
- `{ q: "budget", rows: 10 }` ≡ `{ q: "budget&rows=10" }` → both canonicalize to `q=budget&rows=10` - `{ filters: { a: "b" } }` ≡ `{ filters: '{"a":"b"}' }` → both canonicalize to `filters={"a":"b"}` (object-vs-string ambiguity)
An attacker can reproduce **any** target canonical string by injecting it into the alphabetically-first parameter, so the collision is general, not incidental.
## Impact
- **Cache poisoning / confusion.** On a shared cache (caching is enabled by default; the Cloudflare Workers deployment uses the shared `caches.default`, and a Node HTTP instance shares one in-process LRU across all clients), an attacker primes a colliding entry so that another client's genuinely different query receives the attacker-chosen response for the same portal. - **Integrity of results.** Victims receive data for a query they did not make (wrong dataset list, wrong record set), undermining trust in tool output. - **Chains with indirect prompt injection (advisory #07).** The attacker's colliding request can be one whose upstream response surfaces an attacker-controlled dataset (with malicious `notes`/`title`); the victim's benign query then serves that poisoned content to the model — delivering prompt injection via the cache, without the victim ever querying the malicious dataset.
Confidentiality impact is low (same-portal public data); the primary damage is integrity. `AC:H` reflects the need for caching to be enabled and a shared instance plus priming before the victim's request populates the entry.
## Proof of concept
`poc/cache-collision-poc.mjs` primes a single-param request and shows a victim's distinct two-param request being served the attacker-primed entry:
``` attacker canonical : q=budget&rows=10 victim canonical : q=budget&rows=10 same cache key : true victim served from cache: true victim RECEIVED : RESULT_FOR({"q":"budget&rows=10"}) victim EXPECTED : RESULT_FOR({"q":"budget","rows":10}) ```
## Remediation
- Build the cache key from an unambiguous, injection-proof encoding: hash a structured, canonical JSON (with typed values) or percent-encode/escape each key and value before joining, and use a separator that cannot appear in the encoded fields. Include a type tag so `{a:{...}}` (object) and `{a:"..."}` (string) never coincide. - Consider partitioning the cache per client/tenant on shared deployments so one client cannot influence another's entries.
Are you affected?
Enter the version of the package you're using.
Affected packages
0Fixed in: 0.4.112npm install @aborruso/ckan-mcp-server@0.4.112References
- https://github.com/ondata/ckan-mcp-server/security/advisories/GHSA-78x9-fhhx-v2g6[WEB]
- https://nvd.nist.gov/vuln/detail/CVE-2026-73846[ADVISORY]
- https://github.com/ondata/ckan-mcp-server/commit/8e1522f9bbfa1f3b21550f17887f60f133e24151[WEB]
- https://github.com/ondata/ckan-mcp-server[PACKAGE]
- https://github.com/ondata/ckan-mcp-server/releases/tag/v0.4.112[WEB]