SQl injection in cube-js
Description
cube-js is a headless business intelligence platform. In version 0.31.23 all authenticated Cube clients could bypass SQL row-level security and run arbitrary SQL via the newly introduced /v1/sql-runner endpoint. This issue has been resolved in version 0.31.24. Users are advised to either upgrade to 0.31.24 or to downgrade to 0.31.22. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
@cubejs-backend/api-gatewaynpm | >= 0.31.23, < 0.31.24 | 0.31.24 |
Affected products
1Patches
23c614674fed6Revert "feat(api-gateway, server-core): Added dataSources list to extended meta (#5743)" (#5785)
3 files changed · +3 −59
packages/cubejs-api-gateway/src/gateway.ts+2 −2 modified@@ -448,7 +448,7 @@ class ApiGateway { const metaConfigExtended = await this.getCompilerApi(context).metaConfigExtended({ requestId: context.requestId, }); - const { metaConfig, cubeDefinitions, dataSources } = metaConfigExtended; + const { metaConfig, cubeDefinitions } = metaConfigExtended; const cubes = this.filterVisibleItemsInMeta(context, metaConfig) .map((meta) => meta.config) @@ -466,7 +466,7 @@ class ApiGateway { joins: transformJoins(cubeDefinitions[cube.name]?.joins), preAggregations: transformPreAggregations(cubeDefinitions[cube.name]?.preAggregations), })); - res({ cubes, dataSources }); + res({ cubes }); } catch (e) { this.handleError({ e,
packages/cubejs-server-core/src/core/CompilerApi.js+1 −6 modified@@ -66,10 +66,6 @@ export class CompilerApi { return this.compilers; } - async getDataSources(cubeEvaluator) { - return Promise.all(cubeEvaluator.cubeNames().map(async cube => cubeEvaluator.cubeFromPath(cube).dataSource ?? 'default')); - } - async createQueryFactory(compilers) { const { cubeEvaluator } = compilers; @@ -184,10 +180,9 @@ export class CompilerApi { } async metaConfigExtended(options) { - const { metaTransformer, cubeEvaluator } = await this.getCompilers(options); + const { metaTransformer } = await this.getCompilers(options); return { metaConfig: metaTransformer?.cubes, - dataSources: await this.getDataSources(cubeEvaluator), cubeDefinitions: metaTransformer?.cubeEvaluator?.cubeDefinitions, }; }
packages/cubejs-server-core/test/unit/index.test.ts+0 −51 modified@@ -52,34 +52,6 @@ cube('Bar', { ]), }; -const repositoryWithDataSource: SchemaFileRepository = { - localPath: () => __dirname, - dataSchemaFiles: () => Promise.resolve([ - { - fileName: 'main.js', content: ` -cube('Bar', { - sql: 'select * from bar', - - measures: { - count: { - type: 'count' - } - }, - - dataSource: 'dataSource', - - dimensions: { - time: { - sql: 'timestamp', - type: 'time' - } - } -}); -`, - }, - ]), -}; - const repositoryWithoutContent: SchemaFileRepository = { localPath: () => __dirname, dataSchemaFiles: () => Promise.resolve([{ fileName: 'main.js', content: '' }]), @@ -363,29 +335,6 @@ describe('index.test', () => { expect(metaConfigExtended).toHaveProperty('metaConfig'); expect(metaConfigExtended.metaConfig.length).toBeGreaterThan(0); expect(metaConfigExtended).toHaveProperty('cubeDefinitions'); - expect(metaConfigExtended).toHaveProperty('dataSources'); - expect(metaConfigExtended.dataSources).toEqual(['default']); - expect(metaConfigExtendedSpy).toHaveBeenCalled(); - metaConfigExtendedSpy.mockClear(); - }); - }); - - describe('CompilerApi with dataSource', () => { - const logger = jest.fn(() => {}); - const compilerApi = new CompilerApi( - repositoryWithDataSource, - async () => 'mysql', - { logger } - ); - const metaConfigExtendedSpy = jest.spyOn(compilerApi, 'metaConfigExtended'); - - test('CompilerApi metaConfigExtended', async () => { - const metaConfigExtended = await compilerApi.metaConfigExtended({ requestId: 'XXX' }); - expect(metaConfigExtended).toHaveProperty('metaConfig'); - expect(metaConfigExtended.metaConfig.length).toBeGreaterThan(0); - expect(metaConfigExtended).toHaveProperty('cubeDefinitions'); - expect(metaConfigExtended).toHaveProperty('dataSources'); - expect(metaConfigExtended.dataSources).toEqual(['dataSource']); expect(metaConfigExtendedSpy).toHaveBeenCalled(); metaConfigExtendedSpy.mockClear(); });
f1140de508e3Revert "chore(cubejs-api-gateway): added endpoint to run sql query directly (#5723)" (#5784)
2 files changed · +0 −113
packages/cubejs-api-gateway/src/gateway.ts+0 −61 modified@@ -251,19 +251,6 @@ class ApiGateway { } })); - app.post( - `${this.basePath}/v1/sql-runner`, - jsonParser, - userMiddlewares, - async (req: Request, res: Response) => { - await this.sqlRunner({ - query: req.body.query, - context: req.context!, - res: this.resToResultFn(res), - }); - } - ); - app.get(`${this.basePath}/v1/run-scheduled-refresh`, userMiddlewares, (async (req, res) => { await this.runScheduledRefresh({ queryingOptions: req.query.queryingOptions, @@ -1083,54 +1070,6 @@ class ApiGateway { } } - public async sqlRunner({ query, context, res }: QueryRequest) { - const requestStarted = new Date(); - try { - if (!query) { - throw new UserError( - 'A user\'s query must contain a body' - ); - } - - if (!(query as Record<string, any>).query) { - throw new UserError( - 'A user\'s query must contain at least one query param.' - ); - } - - query = { - ...query, - requestId: context.requestId - }; - - this.log( - { - type: 'Load SQL Runner Request', - query, - }, - context - ); - - const result = await this.getAdapterApi(context).executeQuery(query); - - this.log( - { - type: 'Load SQL Runner Request Success', - query, - duration: this.duration(requestStarted), - dbType: result.dbType, - }, - context - ); - - res(result); - } catch (e) { - this.handleError({ - e, context, query, res, requestStarted - }); - } - } - protected createSecurityContextExtractor(options?: JWTOptions): SecurityContextExtractorFn { if (options?.claimsNamespace) { return (ctx: Readonly<RequestContext>) => {
packages/cubejs-api-gateway/test/index.test.ts+0 −52 modified@@ -339,58 +339,6 @@ describe('API Gateway', () => { expect(res.body.query.measures).toStrictEqual(['Foo.bar']); }); - test('post http method for sql-runner route required params', async () => { - const { app } = createApiGateway(); - - const res = await request(app) - .post('/cubejs-api/v1/sql-runner') - .set('Content-type', 'application/json') - .set( - 'Authorization', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M' - ) - .send({}) - .expect(400); - - expect(res.body && res.body.error).toStrictEqual('A user\'s query must contain a body'); - - const res2 = await request(app) - .post('/cubejs-api/v1/sql-runner') - .set('Content-type', 'application/json') - .set( - 'Authorization', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M' - ) - .send({ query: { query: '' } }) - .expect(400); - - expect(res2.body && res2.body.error).toStrictEqual( - 'A user\'s query must contain at least one query param.' - ); - }); - - test('post http method for sql-runner route', async () => { - const { app } = createApiGateway(); - - const query = { - query: 'SELECT * FROM Foo', - }; - - const res = await request(app) - .post('/cubejs-api/v1/sql-runner') - .set('Content-type', 'application/json') - .set( - 'Authorization', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M' - ) - .send({ query }) - .expect(200); - - expect(res.body.data).toStrictEqual([ - { foo__bar: 42 }, - ]); - }); - test('meta endpoint to get schema information', async () => { const { app } = createApiGateway();
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
5- github.com/advisories/GHSA-6jqm-3c9g-pch7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-23510ghsaADVISORY
- github.com/cube-js/cube.js/commit/3c614674fed6ca17df08bbba8c835ef110167570ghsax_refsource_MISCWEB
- github.com/cube-js/cube.js/commit/f1140de508e359970ac82b50bae1c4bf152f6041ghsax_refsource_MISCWEB
- github.com/cube-js/cube.js/security/advisories/GHSA-6jqm-3c9g-pch7ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.