@@ -2700,6 +2700,90 @@ describe('(GHSA-9xp9-j92r-p88v) Stack overflow process crash via deeply nested q
27002700 ) ;
27012701 } ) ;
27022702
2703+ it ( 'rejects deeply nested query before transform pipeline processes it' , async ( ) => {
2704+ await reconfigureServer ( {
2705+ requestComplexity : { queryDepth : 10 } ,
2706+ } ) ;
2707+ const auth = require ( '../lib/Auth' ) ;
2708+ const rest = require ( '../lib/rest' ) ;
2709+ const config = Config . get ( 'test' ) ;
2710+ // Depth 50 bypasses the fix because RestQuery.js transform pipeline
2711+ // recursively traverses the structure before validateQuery() is reached
2712+ let where = { username : 'test' } ;
2713+ for ( let i = 0 ; i < 50 ; i ++ ) {
2714+ where = { $and : [ where ] } ;
2715+ }
2716+ await expectAsync (
2717+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
2718+ ) . toBeRejectedWith (
2719+ jasmine . objectContaining ( {
2720+ message : jasmine . stringMatching ( / Q u e r y c o n d i t i o n n e s t i n g d e p t h e x c e e d s m a x i m u m a l l o w e d d e p t h / ) ,
2721+ } )
2722+ ) ;
2723+ } ) ;
2724+
2725+ it ( 'rejects deeply nested query via REST API without authentication' , async ( ) => {
2726+ await reconfigureServer ( {
2727+ requestComplexity : { queryDepth : 10 } ,
2728+ } ) ;
2729+ let where = { username : 'test' } ;
2730+ for ( let i = 0 ; i < 50 ; i ++ ) {
2731+ where = { $or : [ where ] } ;
2732+ }
2733+ await expectAsync (
2734+ request ( {
2735+ method : 'GET' ,
2736+ url : `${ Parse . serverURL } /classes/_User` ,
2737+ headers : {
2738+ 'X-Parse-Application-Id' : Parse . applicationId ,
2739+ 'X-Parse-REST-API-Key' : 'rest' ,
2740+ } ,
2741+ qs : { where : JSON . stringify ( where ) } ,
2742+ } )
2743+ ) . toBeRejectedWith (
2744+ jasmine . objectContaining ( {
2745+ data : jasmine . objectContaining ( {
2746+ code : Parse . Error . INVALID_QUERY ,
2747+ } ) ,
2748+ } )
2749+ ) ;
2750+ } ) ;
2751+
2752+ it ( 'rejects deeply nested $nor query before transform pipeline' , async ( ) => {
2753+ await reconfigureServer ( {
2754+ requestComplexity : { queryDepth : 10 } ,
2755+ } ) ;
2756+ const auth = require ( '../lib/Auth' ) ;
2757+ const rest = require ( '../lib/rest' ) ;
2758+ const config = Config . get ( 'test' ) ;
2759+ let where = { username : 'test' } ;
2760+ for ( let i = 0 ; i < 50 ; i ++ ) {
2761+ where = { $nor : [ where ] } ;
2762+ }
2763+ await expectAsync (
2764+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
2765+ ) . toBeRejectedWith (
2766+ jasmine . objectContaining ( {
2767+ message : jasmine . stringMatching ( / Q u e r y c o n d i t i o n n e s t i n g d e p t h e x c e e d s m a x i m u m a l l o w e d d e p t h / ) ,
2768+ } )
2769+ ) ;
2770+ } ) ;
2771+
2772+ it ( 'allows queries within the depth limit' , async ( ) => {
2773+ await reconfigureServer ( {
2774+ requestComplexity : { queryDepth : 10 } ,
2775+ } ) ;
2776+ const auth = require ( '../lib/Auth' ) ;
2777+ const rest = require ( '../lib/rest' ) ;
2778+ const config = Config . get ( 'test' ) ;
2779+ let where = { username : 'test' } ;
2780+ for ( let i = 0 ; i < 5 ; i ++ ) {
2781+ where = { $or : [ where ] } ;
2782+ }
2783+ const result = await rest . find ( config , auth . nobody ( config ) , '_User' , where ) ;
2784+ expect ( result . results ) . toBeDefined ( ) ;
2785+ } ) ;
2786+
27032787 describe ( '(GHSA-wjqw-r9x4-j59v) Empty authData session issuance bypass' , ( ) => {
27042788 const signupHeaders = {
27052789 'Content-Type' : 'application/json' ,
0 commit comments