VYPR
Medium severity5.3NVD Advisory· Published Mar 20, 2026· Updated Apr 17, 2026

CVE-2026-33060

CVE-2026-33060

Description

CKAN MCP Server is a tool for querying CKAN open data portals. Versions prior to 0.4.85 provide tools including ckan_package_search and sparql_query that accept a base_url parameter, making HTTP requests to arbitrary endpoints without restriction. A CKAN portal client has no legitimate reason to contact cloud metadata or internal network services. There is no URL validation on base_url parameter. No private IP blocking (RFC 1918, link-local 169.254.x.x), no cloud metadata blocking. The sparql_query and ckan_datastore_search_sql tools also accept arbitrary base URLs and expose injection surfaces. An attack can lead to internal network scanning, cloud metadata theft (IAM credentials via IMDS at 169.254.169.254), potential SQL/SPARQL injection via unsanitized query parameters. Attack requires prompt injection to control the base_url parameter. This issue has been fixed in version 0.4.85.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@aborruso/ckan-mcp-servernpm
< 0.4.850.4.85

Affected products

1

Patches

1
0a602bff2f44

fix: eb.ref(col, '->$').key(key) is injectable. (#1727)

https://github.com/kysely-org/kyselyIgal KlebanovMar 4, 2026via ghsa
4 files changed · +35 3
  • src/query-compiler/default-query-compiler.ts+5 1 modified
    @@ -1625,7 +1625,11 @@ export class DefaultQueryCompiler
     
         this.append(isArrayLocation ? '[' : '.')
     
    -    this.append(String(node.value))
    +    this.append(
    +      typeof node.value === 'string'
    +        ? this.sanitizeStringLiteral(node.value)
    +        : String(node.value),
    +    )
     
         if (isArrayLocation) {
           this.append(']')
    
  • test/node/src/sanitize-identifiers.test.ts+0 1 modified
    @@ -6,7 +6,6 @@ import {
       TestContext,
       Person,
       testSql,
    -  NOT_SUPPORTED,
       DIALECTS,
     } from './test-setup.js'
     
    
  • test/node/src/sql-injection.test.ts+27 1 modified
    @@ -1,6 +1,6 @@
     import { expect } from 'chai'
     import { sql } from '../../../'
    -import { destroyTest, DIALECTS, initTest, TestContext } from './test-setup'
    +import { destroyTest, DIALECTS, initTest, type TestContext } from './test-setup'
     
     for (const dialect of DIALECTS) {
       describe(`${dialect}: select`, () => {
    @@ -56,6 +56,32 @@ for (const dialect of DIALECTS) {
           expect(results.rows).to.have.length(0)
           await assertDidNotDropTable(ctx, 'person')
         })
    +
    +    if (dialect === 'mysql') {
    +      it('should not allow SQL injection in $.key JSON paths', async () => {
    +        const injection =
    +          `first' as ${identifierWrapper}first${identifierWrapper} from ${identifierWrapper}people${identifierWrapper}; drop table ${identifierWrapper}person${identifierWrapper} -- ` as never
    +
    +        const query = ctx.db
    +          .with('people', () =>
    +            ctx.db
    +              .selectFrom('person')
    +              .select(
    +                sql<{ first: string }>`json_object('first', first_name)`.as(
    +                  'data',
    +                ),
    +              ),
    +          )
    +          .selectFrom('people')
    +          .select((eb) => eb.ref('data', '->$').key(injection).as('first'))
    +
    +        expect(query.compile().sql).to.equal(
    +          `with ${identifierWrapper}people${identifierWrapper} as (select json_object('first', first_name) as ${identifierWrapper}data${identifierWrapper} from ${identifierWrapper}person${identifierWrapper}) select ${identifierWrapper}data${identifierWrapper}->'$.first'' as ${identifierWrapper}first${identifierWrapper} from ${identifierWrapper}people${identifierWrapper}; drop table ${identifierWrapper}person${identifierWrapper} -- ' as ${identifierWrapper}first${identifierWrapper} from ${identifierWrapper}people${identifierWrapper}`,
    +        )
    +        await ctx.db.executeQuery(query)
    +        await assertDidNotDropTable(ctx, 'person')
    +      })
    +    }
       })
     }
     
    
  • test/node/src/test-setup.ts+3 0 modified
    @@ -138,6 +138,9 @@ const MYSQL_CONFIG: PoolOptions = {
       bigNumberStrings: true,
     
       connectionLimit: POOL_SIZE,
    +
    +  // used in sql injection tests.
    +  multipleStatements: true,
     }
     
     const MSSQL_CONFIG: ConnectionConfiguration = {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.