@@ -4142,3 +4142,67 @@ describe('(GHSA-6qh5-m6g3-xhq6) LiveQuery query depth DoS via deeply nested subs
41424142 expect ( subscription ) . toBeDefined ( ) ;
41434143 } ) ;
41444144} ) ;
4145+
4146+ describe ( '(GHSA-g4cf-xj29-wqqr) DoS via unindexed database query for unconfigured auth providers' , ( ) => {
4147+ it ( 'should not query database for unconfigured auth provider on signup' , async ( ) => {
4148+ const databaseAdapter = Config . get ( Parse . applicationId ) . database . adapter ;
4149+ const spy = spyOn ( databaseAdapter , 'find' ) . and . callThrough ( ) ;
4150+ await expectAsync (
4151+ new Parse . User ( ) . save ( { authData : { nonExistentProvider : { id : 'test123' } } } )
4152+ ) . toBeRejectedWith (
4153+ new Parse . Error ( Parse . Error . UNSUPPORTED_SERVICE , 'This authentication method is unsupported.' )
4154+ ) ;
4155+ const authDataQueries = spy . calls . all ( ) . filter ( call => {
4156+ const query = call . args [ 2 ] ;
4157+ return query ?. $or ?. some ( q => q [ 'authData.nonExistentProvider.id' ] ) ;
4158+ } ) ;
4159+ expect ( authDataQueries . length ) . toBe ( 0 ) ;
4160+ } ) ;
4161+
4162+ it ( 'should not query database for unconfigured auth provider on challenge' , async ( ) => {
4163+ const databaseAdapter = Config . get ( Parse . applicationId ) . database . adapter ;
4164+ const spy = spyOn ( databaseAdapter , 'find' ) . and . callThrough ( ) ;
4165+ await expectAsync (
4166+ request ( {
4167+ method : 'POST' ,
4168+ url : Parse . serverURL + '/challenge' ,
4169+ headers : {
4170+ 'X-Parse-Application-Id' : Parse . applicationId ,
4171+ 'X-Parse-REST-API-Key' : 'rest' ,
4172+ 'Content-Type' : 'application/json' ,
4173+ } ,
4174+ body : JSON . stringify ( {
4175+ authData : { nonExistentProvider : { id : 'test123' } } ,
4176+ challengeData : { nonExistentProvider : { token : 'abc' } } ,
4177+ } ) ,
4178+ } )
4179+ ) . toBeRejected ( ) ;
4180+ const authDataQueries = spy . calls . all ( ) . filter ( call => {
4181+ const query = call . args [ 2 ] ;
4182+ return query ?. $or ?. some ( q => q [ 'authData.nonExistentProvider.id' ] ) ;
4183+ } ) ;
4184+ expect ( authDataQueries . length ) . toBe ( 0 ) ;
4185+ } ) ;
4186+
4187+ it ( 'should still query database for configured auth provider' , async ( ) => {
4188+ await reconfigureServer ( {
4189+ auth : {
4190+ myConfiguredProvider : {
4191+ module : {
4192+ validateAppId : ( ) => Promise . resolve ( ) ,
4193+ validateAuthData : ( ) => Promise . resolve ( ) ,
4194+ } ,
4195+ } ,
4196+ } ,
4197+ } ) ;
4198+ const databaseAdapter = Config . get ( Parse . applicationId ) . database . adapter ;
4199+ const spy = spyOn ( databaseAdapter , 'find' ) . and . callThrough ( ) ;
4200+ const user = new Parse . User ( ) ;
4201+ await user . save ( { authData : { myConfiguredProvider : { id : 'validId' , token : 'validToken' } } } ) ;
4202+ const authDataQueries = spy . calls . all ( ) . filter ( call => {
4203+ const query = call . args [ 2 ] ;
4204+ return query ?. $or ?. some ( q => q [ 'authData.myConfiguredProvider.id' ] ) ;
4205+ } ) ;
4206+ expect ( authDataQueries . length ) . toBeGreaterThan ( 0 ) ;
4207+ } ) ;
4208+ } ) ;
0 commit comments