-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
p5.js version
latest
What is your operating system?
None
Web browser and version
all
Actual Behavior
The updateProject function in server/controllers/project.controller.js uses mass-assignment vulnerability by directly passing req.body to MongoDB's $set operator without field whitelisting. This allows authenticated users to overwrite any field in the project document, including critical fields like user (ownership), visibility, slug, and internal fields.
Location:
- File:
server/controllers/project.controller.js - Lines: 51-54
Current Code:
const updatedProject = await Project.findByIdAndUpdate(
req.params.project_id,
{
$set: req.body // CRITICAL: No field whitelisting
},
{
new: true,
runValidators: true
}
)Expected Behavior
Only whitelisted fields should be updatable. The user field should never be modifiable through the update endpoint. Ownership changes should require a separate, properly secured endpoint.
Proposed Fix:
export async function updateProject(req, res) {
try {
const project = await Project.findById(req.params.project_id).exec();
if (!project) {
res.status(404).send({
success: false,
message: 'Project with that id does not exist.'
});
return;
}
if (!project.user.equals(req.user._id)) {
res.status(403).send({
success: false,
message: 'Session does not match owner of project.'
});
return;
}
if (
req.body.updatedAt &&
isAfter(new Date(project.updatedAt), new Date(req.body.updatedAt))
) {
res.status(409).send({
success: false,
message: 'Attempted to save stale version of project.'
});
return;
}
// FIX: Whitelist allowed fields
const allowedFields = ['name', 'files', 'updatedAt'];
const updateData = {};
allowedFields.forEach(field => {
if (req.body[field] !== undefined) {
updateData[field] = req.body[field];
}
});
const updatedProject = await Project.findByIdAndUpdate(
req.params.project_id,
{ $set: updateData },
{
new: true,
runValidators: true
}
)
.populate('user', 'username')
.exec();
// ... rest of the function
} catch (error) {
console.error(error);
res.status(500).json({ success: false });
}
}Steps to reproduce
- Authenticate as a regular user (e.g.,
user1) - Create a project you own (or use an existing project you own)
- Get the project ID from the response or URL
- Send a PUT request to
/editor/projects/:project_idwith your session cookie and malicious payload:{ "name": "Hacked Project", "user": "<another_user_id>", "visibility": "Public", "slug": "malicious-slug" } - Verify that the project ownership has been transferred to
<another_user_id>by checking the response or querying the project - Verify that unauthorized fields like
visibility,slug, andusercan be modified even though they shouldn't be updatable through this endpoint
Note: The ownership check at line 34 only verifies you own the project BEFORE the update. Once you pass that check, $set: req.body overwrites ALL fields including user, allowing you to transfer your own project to another user or modify any other field.