@@ -5103,4 +5103,123 @@ describe('(GHSA-p2w6-rmh7-w8q3) SQL Injection via aggregate and distinct field n
51035103 expect ( response . data . authData ?. mfa ) . toEqual ( { status : 'enabled' } ) ;
51045104 } ) ;
51055105 } ) ;
5106+
5107+ describe ( '(GHSA-q3p6-g7c4-829c) GraphQL endpoint ignores allowOrigin server option' , ( ) => {
5108+ let httpServer ;
5109+ const gqlPort = 13398 ;
5110+
5111+ const gqlHeaders = {
5112+ 'X-Parse-Application-Id' : 'test' ,
5113+ 'X-Parse-Javascript-Key' : 'test' ,
5114+ 'Content-Type' : 'application/json' ,
5115+ } ;
5116+
5117+ async function setupGraphQLServer ( serverOptions = { } ) {
5118+ if ( httpServer ) {
5119+ await new Promise ( resolve => httpServer . close ( resolve ) ) ;
5120+ }
5121+ const server = await reconfigureServer ( serverOptions ) ;
5122+ const expressApp = express ( ) ;
5123+ httpServer = http . createServer ( expressApp ) ;
5124+ expressApp . use ( '/parse' , server . app ) ;
5125+ const parseGraphQLServer = new ParseGraphQLServer ( server , {
5126+ graphQLPath : '/graphql' ,
5127+ } ) ;
5128+ parseGraphQLServer . applyGraphQL ( expressApp ) ;
5129+ await new Promise ( resolve => httpServer . listen ( { port : gqlPort } , resolve ) ) ;
5130+ return parseGraphQLServer ;
5131+ }
5132+
5133+ afterEach ( async ( ) => {
5134+ if ( httpServer ) {
5135+ await new Promise ( resolve => httpServer . close ( resolve ) ) ;
5136+ httpServer = null ;
5137+ }
5138+ } ) ;
5139+
5140+ it ( 'should reflect allowed origin when allowOrigin is configured' , async ( ) => {
5141+ await setupGraphQLServer ( { allowOrigin : 'https://example.com' } ) ;
5142+ const response = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5143+ method : 'POST' ,
5144+ headers : { ...gqlHeaders , Origin : 'https://example.com' } ,
5145+ body : JSON . stringify ( { query : '{ health }' } ) ,
5146+ } ) ;
5147+ expect ( response . status ) . toBe ( 200 ) ;
5148+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://example.com' ) ;
5149+ } ) ;
5150+
5151+ it ( 'should not reflect unauthorized origin when allowOrigin is configured' , async ( ) => {
5152+ await setupGraphQLServer ( { allowOrigin : 'https://example.com' } ) ;
5153+ const response = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5154+ method : 'POST' ,
5155+ headers : { ...gqlHeaders , Origin : 'https://unauthorized.example.net' } ,
5156+ body : JSON . stringify ( { query : '{ health }' } ) ,
5157+ } ) ;
5158+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . not . toBe ( 'https://unauthorized.example.net' ) ;
5159+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://example.com' ) ;
5160+ } ) ;
5161+
5162+ it ( 'should support multiple allowed origins' , async ( ) => {
5163+ await setupGraphQLServer ( { allowOrigin : [ 'https://a.example.com' , 'https://b.example.com' ] } ) ;
5164+ const responseA = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5165+ method : 'POST' ,
5166+ headers : { ...gqlHeaders , Origin : 'https://a.example.com' } ,
5167+ body : JSON . stringify ( { query : '{ health }' } ) ,
5168+ } ) ;
5169+ expect ( responseA . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://a.example.com' ) ;
5170+
5171+ const responseB = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5172+ method : 'POST' ,
5173+ headers : { ...gqlHeaders , Origin : 'https://b.example.com' } ,
5174+ body : JSON . stringify ( { query : '{ health }' } ) ,
5175+ } ) ;
5176+ expect ( responseB . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://b.example.com' ) ;
5177+
5178+ const responseUnauthorized = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5179+ method : 'POST' ,
5180+ headers : { ...gqlHeaders , Origin : 'https://unauthorized.example.net' } ,
5181+ body : JSON . stringify ( { query : '{ health }' } ) ,
5182+ } ) ;
5183+ expect ( responseUnauthorized . headers . get ( 'access-control-allow-origin' ) ) . not . toBe ( 'https://unauthorized.example.net' ) ;
5184+ expect ( responseUnauthorized . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://a.example.com' ) ;
5185+ } ) ;
5186+
5187+ it ( 'should default to wildcard when allowOrigin is not configured' , async ( ) => {
5188+ await setupGraphQLServer ( ) ;
5189+ const response = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5190+ method : 'POST' ,
5191+ headers : { ...gqlHeaders , Origin : 'https://example.com' } ,
5192+ body : JSON . stringify ( { query : '{ health }' } ) ,
5193+ } ) ;
5194+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . toBe ( '*' ) ;
5195+ } ) ;
5196+
5197+ it ( 'should handle OPTIONS preflight with configured allowOrigin' , async ( ) => {
5198+ await setupGraphQLServer ( { allowOrigin : 'https://example.com' } ) ;
5199+ const response = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5200+ method : 'OPTIONS' ,
5201+ headers : {
5202+ Origin : 'https://example.com' ,
5203+ 'Access-Control-Request-Method' : 'POST' ,
5204+ 'Access-Control-Request-Headers' : 'X-Parse-Application-Id, Content-Type' ,
5205+ } ,
5206+ } ) ;
5207+ expect ( response . status ) . toBe ( 200 ) ;
5208+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://example.com' ) ;
5209+ } ) ;
5210+
5211+ it ( 'should not reflect unauthorized origin in OPTIONS preflight' , async ( ) => {
5212+ await setupGraphQLServer ( { allowOrigin : 'https://example.com' } ) ;
5213+ const response = await fetch ( `http://localhost:${ gqlPort } /graphql` , {
5214+ method : 'OPTIONS' ,
5215+ headers : {
5216+ Origin : 'https://unauthorized.example.net' ,
5217+ 'Access-Control-Request-Method' : 'POST' ,
5218+ 'Access-Control-Request-Headers' : 'X-Parse-Application-Id, Content-Type' ,
5219+ } ,
5220+ } ) ;
5221+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . not . toBe ( 'https://unauthorized.example.net' ) ;
5222+ expect ( response . headers . get ( 'access-control-allow-origin' ) ) . toBe ( 'https://example.com' ) ;
5223+ } ) ;
5224+ } ) ;
51065225} ) ;
0 commit comments