@@ -1380,6 +1380,51 @@ describe('(GHSA-gqpp-xgvh-9h7h) SQL Injection via dot-notation sub-key name in I
13801380 expect ( elapsed ) . toBeLessThan ( 3000 ) ;
13811381 } ) ;
13821382
1383+ it_only_db ( 'postgres' ) ( 'does not execute injected SQL via double quote in sub-key name' , async ( ) => {
1384+ const obj = new Parse . Object ( 'SubKeyTest' ) ;
1385+ obj . set ( 'stats' , { counter : 0 } ) ;
1386+ await obj . save ( ) ;
1387+
1388+ const start = Date . now ( ) ;
1389+ await request ( {
1390+ method : 'PUT' ,
1391+ url : `http://localhost:8378/1/classes/SubKeyTest/${ obj . id } ` ,
1392+ headers,
1393+ body : JSON . stringify ( {
1394+ 'stats.x" || (SELECT pg_sleep(3))::text || "' : { __op : 'Increment' , amount : 1 } ,
1395+ } ) ,
1396+ } ) . catch ( ( ) => { } ) ;
1397+ const elapsed = Date . now ( ) - start ;
1398+
1399+ // Double quotes break JSON structure inside the CONCAT, producing invalid JSONB.
1400+ // This causes a database error, NOT SQL injection. If injection succeeded,
1401+ // the query would take >= 3 seconds due to pg_sleep.
1402+ expect ( elapsed ) . toBeLessThan ( 3000 ) ;
1403+ } ) ;
1404+
1405+ it_only_db ( 'postgres' ) ( 'does not execute injected SQL via double quote crafted as valid JSONB in sub-key name' , async ( ) => {
1406+ const obj = new Parse . Object ( 'SubKeyTest' ) ;
1407+ obj . set ( 'stats' , { counter : 0 } ) ;
1408+ await obj . save ( ) ;
1409+
1410+ // This payload uses double quotes to craft a sub-key that produces valid JSONB
1411+ // (e.g. '{"x":0,"evil":1}') instead of breaking JSON structure. Even so, both
1412+ // interpolation sites are inside single-quoted SQL strings, so double quotes
1413+ // cannot escape the SQL context — no arbitrary SQL execution is possible.
1414+ const start = Date . now ( ) ;
1415+ await request ( {
1416+ method : 'PUT' ,
1417+ url : `http://localhost:8378/1/classes/SubKeyTest/${ obj . id } ` ,
1418+ headers,
1419+ body : JSON . stringify ( {
1420+ 'stats.x":0,"pg_sleep(3)' : { __op : 'Increment' , amount : 1 } ,
1421+ } ) ,
1422+ } ) . catch ( ( ) => { } ) ;
1423+ const elapsed = Date . now ( ) - start ;
1424+
1425+ expect ( elapsed ) . toBeLessThan ( 3000 ) ;
1426+ } ) ;
1427+
13831428 it_only_db ( 'postgres' ) ( 'allows valid Increment on nested object field with normal sub-key' , async ( ) => {
13841429 const obj = new Parse . Object ( 'SubKeyTest' ) ;
13851430 obj . set ( 'stats' , { counter : 5 } ) ;
0 commit comments