Video Demonstration: Mass Assignment Attack in MongoDB Application
Watch a real-time demonstration of how mass assignment vulnerabilities work in a Node.js and MongoDB application. This video shows an attacker manipulating the balance field during user registration - a critical vulnerability that can lead to financial fraud and privilege escalation.
⚠️ Important: This demonstration is for educational purposes only. Never attempt these attacks on systems you don't own or have explicit permission to test.
📹 Video Demonstration
Complete walkthrough of mass assignment exploitation in a Node.js application
🎯 What This Video Demonstrates
This hands-on video demonstration walks you through:
1. MongoDB Schema Setup
See the vulnerable User schema in MongoDB with mongoose that includes username, password, and balance fields with default values.
2. Balance Manipulation Attack
Watch in real-time as an attacker injects a balance: 500 field during signup to give themselves free money instead of the default balance of 0.
3. Using Postman for Testing
Learn how to use Postman to test API endpoints and demonstrate how attackers can exploit mass assignment vulnerabilities in REST APIs.
📚 Understanding the Demonstration
The Vulnerable Application Setup
The demonstration uses a Node.js application with the following stack:
- Backend: Node.js with Express.js
- Database: MongoDB with Mongoose ODM
- Authentication: bcrypt for password hashing
- API Testing: Postman for sending requests
The Vulnerable Code
The video shows the actual code from the demonstration. Here's what makes it vulnerable:
1. User Schema (User.js):
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const UserSchema = new mongoose.Schema({
username: { type: String, unique: true },
password: { type: String, required: true },
balance: { type: Number, required: true, default: 0 }
});
The schema defines a balance field with a default value of 0. This should only be set by the server, never by user input.
2. Vulnerable SignUp Route (signUp.js):
// ❌ VULNERABLE CODE
const signup = function (req, res) {
// --- attempt to sign up user ---
db.createNewUser(req.body, (user, error) => {
if (error) {
console.log(error)
}
else {
console.log(user)
}
})
}
🚨 The Problem: The code passes req.body directly to createNewUser(), which means ALL fields from the request are accepted, including fields that should never come from user input like balance!
💥 The Attack Demonstration
Step 1: Normal User Signup
First, the video shows a legitimate user registration with only the required fields:
POST http://localhost:3000/auth/sign-up
Content-Type: application/json
{
"username": "test",
"password": "test"
}
Expected Result: User created with balance: 0 (the default value)
// Terminal Output:
{ username: 'test', password: 'test', balance: 0 }
Step 2: The Attack - Injecting Balance Field
Next, the video demonstrates the mass assignment attack by adding a balance field to the request:
POST http://localhost:3000/auth/sign-up
Content-Type: application/json
{
"username": "test",
"password": "test",
"balance": 500 // 🚨 INJECTED FIELD
}
Attack Result: User created with balance: 500 instead of 0!
// Terminal Output (VULNERABLE):
{ username: 'test', password: 'test', balance: 500 }
// 😱 The attacker gave themselves $500 for free!
💥 Critical Impact: An attacker can now sign up with any balance they want! This could lead to:
- Financial fraud - Free money in their account
- System abuse - Unlimited credits or resources
- Business loss - Company loses money on fraudulent accounts
Step 3: Restarting Server & Verifying Persistence
The video shows restarting the Node.js server and testing again to demonstrate this isn't a one-time glitch - it's a persistent vulnerability in the code.
// Terminal shows server restart:
PS C:\Users\DevBox\Desktop\demo-app\server> ^C
PS C:\Users\DevBox\Desktop\demo-app\server> ^C
PS C:\Users\DevBox\Desktop\demo-app\server> node .\index.js
Example app listening on port 3000
---> connected to database
After restart, the same attack still works - confirming it's a code vulnerability, not a temporary bug.
🛡️ The Secure Solution
The video explains how to fix this vulnerability. Here are the proper implementations:
Solution 1: Explicit Field Extraction (Recommended)
// ✅ SECURE CODE
const signup = function (req, res) {
// Only extract the fields we want to accept
const userData = {
username: req.body.username,
password: req.body.password
// balance is NOT included - will use schema default of 0
};
db.createNewUser(userData, (user, error) => {
if (error) {
console.log(error)
}
else {
console.log(user)
}
})
}
Solution 2: Object Destructuring with Whitelisting
// ✅ SECURE CODE (Alternative)
const signup = function (req, res) {
// Destructure only the allowed fields
const { username, password } = req.body;
db.createNewUser({ username, password }, (user, error) => {
if (error) {
console.log(error)
}
else {
console.log(user)
}
})
}
Solution 3: Input Validation Middleware
// ✅ SECURE CODE (Using express-validator)
const { body, validationResult } = require('express-validator');
app.post('/auth/sign-up',
// Validation middleware
body('username').isString().notEmpty(),
body('password').isString().isLength({ min: 6 }),
// Only these fields are validated - others are rejected
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { username, password } = req.body;
db.createNewUser({ username, password }, (user, error) => {
// ...
})
}
);
✅ Result: With these fixes, even if an attacker sends balance: 500, it will be ignored. The user will be created with the schema's default balance: 0.
🔍 Real-World Financial Impact
The balance manipulation shown in the video demonstrates a critical vulnerability with serious consequences:
| Scenario | Impact | Financial Loss |
|---|---|---|
| E-commerce store credits | Attacker creates account with $1000 balance | Direct loss per attack |
| Gaming platform currency | Unlimited in-game currency on signup | Lost revenue from virtual goods |
| SaaS platform credits | Free API calls or service usage | Infrastructure costs + lost subscriptions |
| Banking/Fintech app | Account created with fake balance | Regulatory fines + reputation damage |
🛠️ Tools Used in the Demonstration
1. Visual Studio Code
The video shows VS Code as the development environment, displaying:
- User.js - MongoDB schema with mongoose
- signUp.js - Vulnerable signup route
- Terminal - Server logs showing created users
2. Postman
Postman is used to send HTTP requests to the API, demonstrating:
- POST requests to
http://localhost:3000/auth/sign-up - JSON body with username and password (normal)
- JSON body with injected balance field (attack)
- Viewing responses and errors
3. Node.js Server
The backend server running on port 3000 with:
- Express.js for routing
- MongoDB connection for data persistence
- bcrypt for password hashing
- Console logging to show user creation
💡 Key Takeaways from the Video
- Never pass req.body directly to database operations: Always explicitly define which fields to accept
- MongoDB schemas with defaults aren't enough: Even with
default: 0, user input can override it - Balance and monetary fields are high-value targets: Attackers will always try to manipulate financial data
- Use destructuring or explicit extraction: Only take the fields you need from the request
- Test your APIs with Postman: Add extra fields to requests to verify they're rejected
- Validate input at multiple layers: Use express-validator or similar tools for comprehensive validation
🧪 How to Reproduce This Demonstration
Want to test this yourself? Here's how to set up a similar test environment:
Step 1: Create the Vulnerable App
# Initialize Node.js project
npm init -y
# Install dependencies
npm install express mongoose bcrypt
# Create server files
# - index.js (main server file)
# - User.js (mongoose schema)
# - signUp.js (auth route)
Step 2: Set Up MongoDB
# Option 1: Local MongoDB
# Install from mongodb.com
# Option 2: MongoDB Atlas (free cloud)
# Sign up at mongodb.com/cloud/atlas
# Get connection string
# Add to your code:
mongoose.connect('mongodb://localhost:27017/demo-app');
Step 3: Test with Postman
In Postman:
- Create a new POST request
- Set URL to
http://localhost:3000/auth/sign-up - Set Headers:
Content-Type: application/json - Set Body (raw JSON):
{
"username": "testuser",
"password": "password123",
"balance": 9999999
}
If the server accepts the balance field, it's vulnerable!
📊 Related Vulnerabilities
Mass assignment can be exploited to manipulate various sensitive fields:
Privilege Escalation
{
"username": "hacker",
"isAdmin": true,
"role": "admin"
}
Gain administrator access
Account Takeover
{
"username": "victim",
"userId": "other_user_id",
"ownerId": 12345
}
Modify ownership or user ID
Financial Fraud
{
"username": "thief",
"balance": 1000000,
"credits": 999999
}
Manipulate monetary values
Status Manipulation
{
"username": "faker",
"verified": true,
"approved": true
}
Bypass verification processes
✅ Security Best Practices
Based on the video demonstration, implement these security measures:
Input Whitelisting Checklist:
- ☑️ Extract only expected fields from req.body using destructuring
- ☑️ Never pass req.body directly to database operations or constructors
- ☑️ Set sensitive fields server-side (balance, isAdmin, role, etc.)
- ☑️ Use validation libraries like express-validator or joi
- ☑️ Implement Data Transfer Objects (DTOs) to define allowed fields
- ☑️ Test APIs with extra fields to ensure they're ignored
- ☑️ Review all POST/PUT/PATCH endpoints for mass assignment risks
- ☑️ Enable strict schema validation in MongoDB/Mongoose
- ☑️ Log suspicious requests with unexpected fields
- ☑️ Conduct security code reviews before deployment
🎓 Learning Resources
To learn more about mass assignment and API security:
- OWASP Mass Assignment: Official Cheat Sheet
- Express.js Security Best Practices: Official Guide
- Mongoose Schema Validation: Documentation
- Express Validator: Input Validation Library
- OWASP API Security: Top 10 API Risks
1 Comments
The video is very helpful and informative.
ReplyDelete