E-commerce-project-springBoot-master — Vulnerability Assessment
VULN-1: IDOR — Authorization Bypass in POST /updateuser
Status: ✅ CONFIRMED (Dynamically Verified)
Summary
The POST /updateuser endpoint in UserController accepts a userid parameter directly from the HTTP request without verifying that the authenticated user is authorized to modify the target profile. Any authenticated user (including low-privilege ROLE_NORMAL users) can supply an arbitrary userid to change any other user's password, email, and address — including the administrator's account.
This enables full account takeover: a normal customer can silently change the admin's password and seize control of the entire e-commerce platform.
| Field |
Value |
| CWE |
CWE-639 (Authorization Bypass Through User-Controlled Key) |
| CVSS 3.1 |
8.8 (High) — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Attack Type |
Authenticated IDOR → Privilege Escalation |
| Impact |
Full admin account takeover |
CVE 6-Gate Assessment
| # |
Criterion |
Result |
| 1 |
Complete Source→Sink data flow |
✅ HTTP userid param → UserController.updateUser() → userService.updateUserProfile() → Hibernate UPDATE CUSTOMER |
| 2 |
Exploitable in default configuration |
✅ No custom config required — vulnerability exists in source code |
| 3 |
Successful dynamic PoC |
✅ Password changed admin→"hacked123", verified via BCrypt hash comparison |
| 4 |
Real security impact |
✅ Any user can change admin password → full system compromise |
| 5 |
Not a duplicate |
✅ Unique to this codebase |
| 6 |
Not a configuration error |
✅ Code-level authorization bypass — missing userid ownership check |
Technical Details
Vulnerable Code — UserController.java:updateUser():
@PostMapping("/updateuser")
public String updateUser(
@RequestParam("userid") int userid, // ← USER-CONTROLLED, NO AUTH CHECK
@RequestParam("username") String username,
@RequestParam("email") String email,
@RequestParam("password") String password,
@RequestParam("address") String address) {
userService.updateUserProfile(userid, username, email, password, address);
return "redirect:/profileDisplay";
}
Sink — userService.updateUserProfile():
public void updateUserProfile(int userid, String username, String email, String password, String address) {
User user = this.userDao.getUser(userid);
user.setEmail(email);
user.setPassword(passwordEncoder.encode(password)); // BCrypt encodes attacker-supplied password
user.setAddress(address);
this.userDao.updateUser(user);
}
The userid flows directly from HTTP request → controller → service → DAO without any authorization check. The service method blindly trusts the caller and updates whichever userid is provided.
Attack Chain
Attacker (ROLE_NORMAL)
│
├─[1]─ Login as lisa/765 → gets JSESSIONID + CSRF token
│
├─[2]─ POST /updateuser
│ Body: userid=1&username=admin&password=hacked123&...
│ Cookie: JSESSIONID=<lisa's session>
│ → Server updates admin (id=1) password to BCrypt("hacked123")
│
└─[3]─ Admin password is now "hacked123"
→ Attacker can login as admin
→ Full system compromise
Dynamic PoC Verification
| Step |
Action |
Result |
| 1 |
Reset DB: admin=123, lisa=765 |
✅ |
| 2 |
Login as lisa (normal user) |
✅ 302 → / |
| 3 |
GET /profileDisplay (extract CSRF) |
✅ 200, userid=2 |
| 4 |
POST /updateuser userid=1 password=hacked123 |
✅ 302 → / (accepted) |
| 5 |
DB check: admin password |
✅ Now BCrypt hash (was plaintext "123") |
| 6 |
BCrypt comparison: checkpw("hacked123", hash) |
✅ True — verified |
PoC script: poc_idor_updateuser.py — reproducible, self-resetting.
poc_idor_updateuser.py
Remediation
Add authorization check before updating user profile:
@PostMapping("/updateuser")
public String updateUser(
@RequestParam("userid") int userid,
@RequestParam("username") String username,
// ... other params
Principal principal) { // ← inject authenticated user
// Get the authenticated user's ID from session/security context
int authenticatedUserId = getAuthenticatedUserId(principal);
// Authorization check: user can only modify their own profile
if (userid != authenticatedUserId) {
throw new AccessDeniedException("Not authorized to modify this user");
}
// For admin override, check role:
// if (!hasRole("ADMIN") && userid != authenticatedUserId) { throw ... }
userService.updateUserProfile(userid, username, email, password, address);
return "redirect:/profileDisplay";
}
Additional Notes
- PasswordEncoder: The application uses
BCryptPasswordEncoder (configured in PasswordEncoderConfig.java), so passwords are stored as BCrypt hashes. The IDOR bypasses this protection because the controller passes the raw password through the legitimate encoding pipeline.
- CSRF Protection: Spring Security CSRF is enabled, but the CSRF token only prevents cross-site attacks — it does not prevent same-session IDOR.
- Dual Filter Chain: The admin filter chain (
/admin/**) has a configuration issue where admin login redirects to the user login page, but this does not affect the IDOR exploit — the password change is confirmed via database verification.
- Default Credentials:
basedata.sql ships with admin/123 and lisa/765 in plaintext, making exploitation trivial.
E-commerce-project-springBoot-master — Vulnerability Assessment
VULN-1: IDOR — Authorization Bypass in POST /updateuser
Status: ✅ CONFIRMED (Dynamically Verified)
Summary
The
POST /updateuserendpoint inUserControlleraccepts auseridparameter directly from the HTTP request without verifying that the authenticated user is authorized to modify the target profile. Any authenticated user (including low-privilegeROLE_NORMALusers) can supply an arbitraryuseridto change any other user's password, email, and address — including the administrator's account.This enables full account takeover: a normal customer can silently change the admin's password and seize control of the entire e-commerce platform.
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HCVE 6-Gate Assessment
useridparam →UserController.updateUser()→userService.updateUserProfile()→ HibernateUPDATE CUSTOMERuseridownership checkTechnical Details
Vulnerable Code —
UserController.java:updateUser():Sink —
userService.updateUserProfile():The
useridflows directly from HTTP request → controller → service → DAO without any authorization check. The service method blindly trusts the caller and updates whicheveruseridis provided.Attack Chain
Dynamic PoC Verification
PoC script:
poc_idor_updateuser.py— reproducible, self-resetting.poc_idor_updateuser.py
Remediation
Add authorization check before updating user profile:
Additional Notes
BCryptPasswordEncoder(configured inPasswordEncoderConfig.java), so passwords are stored as BCrypt hashes. The IDOR bypasses this protection because the controller passes the raw password through the legitimate encoding pipeline./admin/**) has a configuration issue where admin login redirects to the user login page, but this does not affect the IDOR exploit — the password change is confirmed via database verification.basedata.sqlships with admin/123 and lisa/765 in plaintext, making exploitation trivial.