@@ -2278,6 +2278,107 @@ describe('(GHSA-w54v-hf9p-8856) User enumeration via email verification endpoint
22782278 } ) ;
22792279} ) ;
22802280
2281+ describe ( '(GHSA-4m9m-p9j9-5hjw) User enumeration via signup endpoint' , ( ) => {
2282+ async function updateCLP ( permissions ) {
2283+ const response = await fetch ( Parse . serverURL + '/schemas/_User' , {
2284+ method : 'PUT' ,
2285+ headers : {
2286+ 'X-Parse-Application-Id' : Parse . applicationId ,
2287+ 'X-Parse-Master-Key' : Parse . masterKey ,
2288+ 'Content-Type' : 'application/json' ,
2289+ } ,
2290+ body : JSON . stringify ( { classLevelPermissions : permissions } ) ,
2291+ } ) ;
2292+ const body = await response . json ( ) ;
2293+ if ( body . error ) {
2294+ throw body ;
2295+ }
2296+ }
2297+
2298+ it ( 'does not reveal existing username when public create CLP is disabled' , async ( ) => {
2299+ const user = new Parse . User ( ) ;
2300+ user . setUsername ( 'existingUser' ) ;
2301+ user . setPassword ( 'password123' ) ;
2302+ await user . signUp ( ) ;
2303+ await Parse . User . logOut ( ) ;
2304+
2305+ await updateCLP ( {
2306+ get : { '*' : true } ,
2307+ find : { '*' : true } ,
2308+ create : { } ,
2309+ update : { '*' : true } ,
2310+ delete : { '*' : true } ,
2311+ addField : { } ,
2312+ } ) ;
2313+
2314+ const response = await request ( {
2315+ url : 'http://localhost:8378/1/classes/_User' ,
2316+ method : 'POST' ,
2317+ body : { username : 'existingUser' , password : 'otherpassword' } ,
2318+ headers : {
2319+ 'X-Parse-Application-Id' : Parse . applicationId ,
2320+ 'X-Parse-REST-API-Key' : 'rest' ,
2321+ 'Content-Type' : 'application/json' ,
2322+ } ,
2323+ } ) . catch ( e => e ) ;
2324+ expect ( response . data . code ) . not . toBe ( Parse . Error . USERNAME_TAKEN ) ;
2325+ expect ( response . data . error ) . not . toContain ( 'Account already exists' ) ;
2326+ expect ( response . data . code ) . toBe ( Parse . Error . OPERATION_FORBIDDEN ) ;
2327+ } ) ;
2328+
2329+ it ( 'does not reveal existing email when public create CLP is disabled' , async ( ) => {
2330+ const user = new Parse . User ( ) ;
2331+ user . setUsername ( 'emailUser' ) ;
2332+ user . setPassword ( 'password123' ) ;
2333+ user . setEmail ( 'existing@example.com' ) ;
2334+ await user . signUp ( ) ;
2335+ await Parse . User . logOut ( ) ;
2336+
2337+ await updateCLP ( {
2338+ get : { '*' : true } ,
2339+ find : { '*' : true } ,
2340+ create : { } ,
2341+ update : { '*' : true } ,
2342+ delete : { '*' : true } ,
2343+ addField : { } ,
2344+ } ) ;
2345+
2346+ const response = await request ( {
2347+ url : 'http://localhost:8378/1/classes/_User' ,
2348+ method : 'POST' ,
2349+ body : { username : 'newUser' , password : 'otherpassword' , email : 'existing@example.com' } ,
2350+ headers : {
2351+ 'X-Parse-Application-Id' : Parse . applicationId ,
2352+ 'X-Parse-REST-API-Key' : 'rest' ,
2353+ 'Content-Type' : 'application/json' ,
2354+ } ,
2355+ } ) . catch ( e => e ) ;
2356+ expect ( response . data . code ) . not . toBe ( Parse . Error . EMAIL_TAKEN ) ;
2357+ expect ( response . data . error ) . not . toContain ( 'Account already exists' ) ;
2358+ expect ( response . data . code ) . toBe ( Parse . Error . OPERATION_FORBIDDEN ) ;
2359+ } ) ;
2360+
2361+ it ( 'still returns username taken error when public create CLP is enabled' , async ( ) => {
2362+ const user = new Parse . User ( ) ;
2363+ user . setUsername ( 'existingUser' ) ;
2364+ user . setPassword ( 'password123' ) ;
2365+ await user . signUp ( ) ;
2366+ await Parse . User . logOut ( ) ;
2367+
2368+ const response = await request ( {
2369+ url : 'http://localhost:8378/1/classes/_User' ,
2370+ method : 'POST' ,
2371+ body : { username : 'existingUser' , password : 'otherpassword' } ,
2372+ headers : {
2373+ 'X-Parse-Application-Id' : Parse . applicationId ,
2374+ 'X-Parse-REST-API-Key' : 'rest' ,
2375+ 'Content-Type' : 'application/json' ,
2376+ } ,
2377+ } ) . catch ( e => e ) ;
2378+ expect ( response . data . code ) . toBe ( Parse . Error . USERNAME_TAKEN ) ;
2379+ } ) ;
2380+ } ) ;
2381+
22812382describe ( '(GHSA-c442-97qw-j6c6) SQL Injection via $regex query operator field name in PostgreSQL adapter' , ( ) => {
22822383 const headers = {
22832384 'Content-Type' : 'application/json' ,
0 commit comments