@@ -2769,6 +2769,69 @@ describe('Vulnerabilities', () => {
27692769 }
27702770 } ) ;
27712771
2772+ describe ( '(GHSA-vr5f-2r24-w5hc) Stored XSS via Content-Type and file extension mismatch' , ( ) => {
2773+ const headers = {
2774+ 'X-Parse-Application-Id' : 'test' ,
2775+ 'X-Parse-REST-API-Key' : 'rest' ,
2776+ } ;
2777+
2778+ it ( 'overrides mismatched Content-Type with extension-derived MIME type on buffered upload' , async ( ) => {
2779+ const adapter = Config . get ( 'test' ) . filesController . adapter ;
2780+ const spy = spyOn ( adapter , 'createFile' ) . and . callThrough ( ) ;
2781+ const content = Buffer . from ( '<script>alert(1)</script>' ) . toString ( 'base64' ) ;
2782+ await request ( {
2783+ method : 'POST' ,
2784+ url : 'http://localhost:8378/1/files/evil.txt' ,
2785+ body : JSON . stringify ( {
2786+ _ApplicationId : 'test' ,
2787+ _JavaScriptKey : 'test' ,
2788+ _ContentType : 'text/html' ,
2789+ base64 : content ,
2790+ } ) ,
2791+ headers,
2792+ } ) ;
2793+ expect ( spy ) . toHaveBeenCalled ( ) ;
2794+ const contentTypeArg = spy . calls . mostRecent ( ) . args [ 2 ] ;
2795+ expect ( contentTypeArg ) . toBe ( 'text/plain' ) ;
2796+ } ) ;
2797+
2798+ it ( 'preserves Content-Type when no file extension is present' , async ( ) => {
2799+ const adapter = Config . get ( 'test' ) . filesController . adapter ;
2800+ const spy = spyOn ( adapter , 'createFile' ) . and . callThrough ( ) ;
2801+ await request ( {
2802+ method : 'POST' ,
2803+ url : 'http://localhost:8378/1/files/noextension' ,
2804+ headers : {
2805+ ...headers ,
2806+ 'Content-Type' : 'image/png' ,
2807+ } ,
2808+ body : Buffer . from ( 'fake png content' ) ,
2809+ } ) ;
2810+ expect ( spy ) . toHaveBeenCalled ( ) ;
2811+ const contentTypeArg = spy . calls . mostRecent ( ) . args [ 2 ] ;
2812+ expect ( contentTypeArg ) . toBe ( 'image/png' ) ;
2813+ } ) ;
2814+
2815+ it ( 'infers Content-Type from extension when none is provided' , async ( ) => {
2816+ const adapter = Config . get ( 'test' ) . filesController . adapter ;
2817+ const spy = spyOn ( adapter , 'createFile' ) . and . callThrough ( ) ;
2818+ const content = Buffer . from ( 'test content' ) . toString ( 'base64' ) ;
2819+ await request ( {
2820+ method : 'POST' ,
2821+ url : 'http://localhost:8378/1/files/data.txt' ,
2822+ body : JSON . stringify ( {
2823+ _ApplicationId : 'test' ,
2824+ _JavaScriptKey : 'test' ,
2825+ base64 : content ,
2826+ } ) ,
2827+ headers,
2828+ } ) ;
2829+ expect ( spy ) . toHaveBeenCalled ( ) ;
2830+ const contentTypeArg = spy . calls . mostRecent ( ) . args [ 2 ] ;
2831+ expect ( contentTypeArg ) . toBe ( 'text/plain' ) ;
2832+ } ) ;
2833+ } ) ;
2834+
27722835 describe ( '(GHSA-9ccr-fpp6-78qf) Schema poisoning via __proto__ bypassing requestKeywordDenylist and addField CLP' , ( ) => {
27732836 const headers = {
27742837 'Content-Type' : 'application/json' ,
0 commit comments