@@ -908,6 +908,86 @@ describe('(GHSA-qpr4-jrj4-6f27) SQL Injection via sort dot-notation field name',
908908 expect ( elapsed ) . toBeLessThan ( 3000 ) ;
909909 } ) ;
910910
911+ it_only_db ( 'postgres' ) ( 'does not execute injection via dollar-sign quoting bypass' , async ( ) => {
912+ // PostgreSQL supports $$string$$ as alternative to 'string'
913+ const obj = new Parse . Object ( 'InjectionTest' ) ;
914+ obj . set ( 'data' , { key : 'value' } ) ;
915+ obj . set ( 'name' , 'original' ) ;
916+ await obj . save ( ) ;
917+
918+ await request ( {
919+ method : 'GET' ,
920+ url : 'http://localhost:8378/1/classes/InjectionTest' ,
921+ headers,
922+ qs : {
923+ order : "data.x' ASC; UPDATE \"InjectionTest\" SET name = $$hacked$$ WHERE true--" ,
924+ } ,
925+ } ) . catch ( ( ) => { } ) ;
926+
927+ const verify = await new Parse . Query ( 'InjectionTest' ) . first ( ) ;
928+ expect ( verify . get ( 'name' ) ) . toBe ( 'original' ) ;
929+ } ) ;
930+
931+ it_only_db ( 'postgres' ) ( 'does not execute injection via tagged dollar quoting bypass' , async ( ) => {
932+ // PostgreSQL supports $tag$string$tag$ as alternative to 'string'
933+ const obj = new Parse . Object ( 'InjectionTest' ) ;
934+ obj . set ( 'data' , { key : 'value' } ) ;
935+ obj . set ( 'name' , 'original' ) ;
936+ await obj . save ( ) ;
937+
938+ await request ( {
939+ method : 'GET' ,
940+ url : 'http://localhost:8378/1/classes/InjectionTest' ,
941+ headers,
942+ qs : {
943+ order : "data.x' ASC; UPDATE \"InjectionTest\" SET name = $t$hacked$t$ WHERE true--" ,
944+ } ,
945+ } ) . catch ( ( ) => { } ) ;
946+
947+ const verify = await new Parse . Query ( 'InjectionTest' ) . first ( ) ;
948+ expect ( verify . get ( 'name' ) ) . toBe ( 'original' ) ;
949+ } ) ;
950+
951+ it_only_db ( 'postgres' ) ( 'does not execute injection via CHR() concatenation bypass' , async ( ) => {
952+ // CHR(104)||CHR(97)||... builds 'hacked' without quotes
953+ const obj = new Parse . Object ( 'InjectionTest' ) ;
954+ obj . set ( 'data' , { key : 'value' } ) ;
955+ obj . set ( 'name' , 'original' ) ;
956+ await obj . save ( ) ;
957+
958+ await request ( {
959+ method : 'GET' ,
960+ url : 'http://localhost:8378/1/classes/InjectionTest' ,
961+ headers,
962+ qs : {
963+ order : "data.x' ASC; UPDATE \"InjectionTest\" SET name = CHR(104)||CHR(97)||CHR(99)||CHR(107) WHERE true--" ,
964+ } ,
965+ } ) . catch ( ( ) => { } ) ;
966+
967+ const verify = await new Parse . Query ( 'InjectionTest' ) . first ( ) ;
968+ expect ( verify . get ( 'name' ) ) . toBe ( 'original' ) ;
969+ } ) ;
970+
971+ it_only_db ( 'postgres' ) ( 'does not execute injection via backslash escape bypass' , async ( ) => {
972+ // Backslash before quote could interact with '' escaping in some configurations
973+ const obj = new Parse . Object ( 'InjectionTest' ) ;
974+ obj . set ( 'data' , { key : 'value' } ) ;
975+ obj . set ( 'name' , 'original' ) ;
976+ await obj . save ( ) ;
977+
978+ await request ( {
979+ method : 'GET' ,
980+ url : 'http://localhost:8378/1/classes/InjectionTest' ,
981+ headers,
982+ qs : {
983+ order : "data.x\\' ASC; UPDATE \"InjectionTest\" SET name = 'hacked' WHERE true--" ,
984+ } ,
985+ } ) . catch ( ( ) => { } ) ;
986+
987+ const verify = await new Parse . Query ( 'InjectionTest' ) . first ( ) ;
988+ expect ( verify . get ( 'name' ) ) . toBe ( 'original' ) ;
989+ } ) ;
990+
911991 it ( 'allows valid dot-notation sort on object field' , async ( ) => {
912992 const obj = new Parse . Object ( 'InjectionTest' ) ;
913993 obj . set ( 'data' , { key : 'value' } ) ;
0 commit comments