VYPR
High severityNVD Advisory· Published Dec 9, 2022· Updated Apr 23, 2025

SQl injection in cube-js

CVE-2022-23510

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.

PackageAffected versionsPatched versions
@cubejs-backend/api-gatewaynpm
>= 0.31.23, < 0.31.240.31.24

Affected products

1

Patches

2
3c614674fed6

Revert "feat(api-gateway, server-core): Added dataSources list to extended meta (#5743)" (#5785)

https://github.com/cube-js/cube.jsMike NitsenkoDec 9, 2022via ghsa
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();
         });
    
f1140de508e3

Revert "chore(cubejs-api-gateway): added endpoint to run sql query directly (#5723)" (#5784)

https://github.com/cube-js/cube.jsMike NitsenkoDec 9, 2022via ghsa
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

News mentions

0

No linked articles in our index yet.