@aborruso/ckan-mcp-server 0.4.127 → 0.4.128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LOG.md +10 -0
  2. package/dist/index.js +9 -3
  3. package/package.json +1 -1
package/LOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # LOG
2
2
 
3
+ ## 2026-09-28
4
+
5
+ ### v0.4.128
6
+
7
+ Ships #556: every redirect hop in `makeCkanRequest` is re-validated (GHSA-279h-fmcr-4rwv), on both the Node/axios and Workers/fetch paths. Smoke 17/17.
8
+
9
+ ### Security: validate every redirect hop in `makeCkanRequest` (GHSA-279h-fmcr-4rwv)
10
+
11
+ `makeCkanRequest` followed up to 5 redirects via axios without re-validating the target. The SSRF-safe agent `lookup` is skipped by Node for IP literals, so a public URL 302-ing to `http://127.0.0.1/` or `169.254.169.254` was followed, and an internal endpoint answering `success: true` was returned in full (reproduced end-to-end via httpbin `redirect-to`). Fix: axios `beforeRedirect` calls `validateServerUrl` on each hop; the Workers `fetch` branch now uses `safeFetch` (`maxHops: 5`). Side effect: `CKAN_ALLOWED_DOMAINS` now applies to redirect targets too, so a portal redirecting to another host needs both listed. The public Worker (no allowlist) is unaffected for public portals.
12
+
3
13
  ## 2026-09-24
4
14
 
5
15
  ### v0.4.127
package/dist/index.js CHANGED
@@ -945,6 +945,12 @@ async function makeCkanRequest(serverUrl, action, params = {}, opts = {}) {
945
945
  timeout: 3e4,
946
946
  responseType: "arraybuffer",
947
947
  maxRedirects: 5,
948
+ // Re-validate every redirect hop: Node skips the agent's `lookup` for IP
949
+ // literals, so a public host 302-ing to e.g. 169.254.169.254 would otherwise
950
+ // be followed. Also enforces CKAN_ALLOWED_DOMAINS on redirect targets.
951
+ beforeRedirect: (redirectOptions) => {
952
+ validateServerUrl(redirectOptions.href);
953
+ },
948
954
  // Never route through HTTP_PROXY/HTTPS_PROXY: a proxy would connect to the
949
955
  // target itself, bypassing the SSRF-safe lookup pinned in the agents below.
950
956
  proxy: false,
@@ -979,7 +985,7 @@ async function makeCkanRequest(serverUrl, action, params = {}, opts = {}) {
979
985
  const timeoutId = setTimeout(() => controller.abort(), 3e4);
980
986
  let response;
981
987
  try {
982
- response = await fetch(fetchUrl, {
988
+ response = await safeFetch(fetchUrl, {
983
989
  method: "GET",
984
990
  signal: controller.signal,
985
991
  headers: {
@@ -987,7 +993,7 @@ async function makeCkanRequest(serverUrl, action, params = {}, opts = {}) {
987
993
  "Accept-Encoding": "identity",
988
994
  "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
989
995
  }
990
- });
996
+ }, { maxHops: 5 });
991
997
  } finally {
992
998
  clearTimeout(timeoutId);
993
999
  }
@@ -6042,7 +6048,7 @@ var registerAllPrompts = (server) => {
6042
6048
  function createServer() {
6043
6049
  return new McpServer({
6044
6050
  name: "ckan-mcp-server",
6045
- version: "0.4.127"
6051
+ version: "0.4.128"
6046
6052
  });
6047
6053
  }
6048
6054
  function registerAll(server) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aborruso/ckan-mcp-server",
3
- "version": "0.4.127",
3
+ "version": "0.4.128",
4
4
  "mcpName": "io.github.aborruso/ckan-mcp-server",
5
5
  "description": "MCP server for interacting with CKAN open data portals",
6
6
  "repository": {