From 62820fb9f7577745a117bd7f19d7797edc3bd77e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 06:07:30 +0000 Subject: [PATCH 1/3] Fix mass assignment vulnerabilities in blog and job controllers Co-authored-by: Adityavanjre <66417028+Adityavanjre@users.noreply.github.com> --- agency/server/controllers/blogController.js | 7 +- agency/server/controllers/jobController.js | 7 +- agency/server/package.json | 6 +- agency/server/tests/massAssignment.test.js | 91 +++++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 agency/server/tests/massAssignment.test.js diff --git a/agency/server/controllers/blogController.js b/agency/server/controllers/blogController.js index fcd4d8ca..8b31b570 100644 --- a/agency/server/controllers/blogController.js +++ b/agency/server/controllers/blogController.js @@ -77,7 +77,12 @@ const updateBlog = async (req, res) => { const blog = await Blog.findById(req.params.id); if (blog) { - Object.assign(blog, req.body); + const allowedFields = ['title', 'author', 'date', 'category', 'image', 'excerpt', 'content', 'readTime', 'tags', 'slug', 'status']; + allowedFields.forEach(field => { + if (req.body[field] !== undefined) { + blog[field] = req.body[field]; + } + }); const updatedBlog = await blog.save(); res.json(updatedBlog); } else { diff --git a/agency/server/controllers/jobController.js b/agency/server/controllers/jobController.js index d1269689..e1627ead 100644 --- a/agency/server/controllers/jobController.js +++ b/agency/server/controllers/jobController.js @@ -43,7 +43,12 @@ const updateJob = async (req, res) => { const job = await Job.findById(req.params.id); if (job) { - Object.assign(job, req.body); + const allowedFields = ['role', 'type', 'location', 'description', 'requirements', 'isActive']; + allowedFields.forEach(field => { + if (req.body[field] !== undefined) { + job[field] = req.body[field]; + } + }); const updatedJob = await job.save(); res.json(updatedJob); } else { diff --git a/agency/server/package.json b/agency/server/package.json index 79d79b51..64e31347 100644 --- a/agency/server/package.json +++ b/agency/server/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "start": "node index.js", - "dev": "nodemon index.js" + "dev": "nodemon index.js", + "test": "jest" }, "dependencies": { "bcryptjs": "^3.0.3", @@ -23,6 +24,7 @@ "nodemailer": "^8.0.2" }, "devDependencies": { + "jest": "^30.4.0", "nodemon": "^3.1.0" } -} +} \ No newline at end of file diff --git a/agency/server/tests/massAssignment.test.js b/agency/server/tests/massAssignment.test.js new file mode 100644 index 00000000..873e072c --- /dev/null +++ b/agency/server/tests/massAssignment.test.js @@ -0,0 +1,91 @@ +const { updateBlog } = require('../controllers/blogController'); +const { updateJob } = require('../controllers/jobController'); +const Blog = require('../models/Blog'); +const Job = require('../models/Job'); + +jest.mock('../models/Blog'); +jest.mock('../models/Job'); + +describe('Mass Assignment Vulnerability Fixes', () => { + let req, res; + + beforeEach(() => { + req = { + params: { id: 'test-id' }, + body: {} + }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis() + }; + jest.clearAllMocks(); + }); + + describe('blogController.updateBlog', () => { + it('should only update allowed fields and ignore unauthorized fields', async () => { + const mockBlogDoc = { + title: 'Old Title', + author: 'Old Author', + save: jest.fn().mockResolvedValue(true) + }; + Blog.findById.mockResolvedValue(mockBlogDoc); + + req.body = { + title: 'New Title', + isAdmin: true, // Vulnerable field attempt + status: 'published', + _id: 'injected-id' // Vulnerable field attempt + }; + + await updateBlog(req, res); + + // Expect the explicitly allowed fields to be updated + expect(mockBlogDoc.title).toBe('New Title'); + expect(mockBlogDoc.status).toBe('published'); + + // Expect unauthorized fields to NOT be assigned + expect(mockBlogDoc.isAdmin).toBeUndefined(); + expect(mockBlogDoc._id).toBeUndefined(); + + // Original un-updated field should remain untouched + expect(mockBlogDoc.author).toBe('Old Author'); + + expect(mockBlogDoc.save).toHaveBeenCalled(); + expect(res.json).toHaveBeenCalledWith(true); // Since save() resolves to true + }); + }); + + describe('jobController.updateJob', () => { + it('should only update allowed fields and ignore unauthorized fields', async () => { + const mockJobDoc = { + role: 'Old Role', + type: 'Full-time', + save: jest.fn().mockResolvedValue(true) + }; + Job.findById.mockResolvedValue(mockJobDoc); + + req.body = { + role: 'New Role', + isActive: false, + isAdmin: true, // Vulnerable field attempt + _id: 'injected-id' // Vulnerable field attempt + }; + + await updateJob(req, res); + + // Expect explicitly allowed fields to be updated + expect(mockJobDoc.role).toBe('New Role'); + expect(mockJobDoc.isActive).toBe(false); + + // Expect unauthorized fields to NOT be assigned + expect(mockJobDoc.isAdmin).toBeUndefined(); + expect(mockJobDoc._id).toBeUndefined(); + + // Original un-updated field should remain untouched + expect(mockJobDoc.type).toBe('Full-time'); + + expect(mockJobDoc.save).toHaveBeenCalled(); + expect(res.json).toHaveBeenCalledWith(true); // Since save() resolves to true + }); + }); +}); From 35d0b1ca9de915f2a4735d5c8ac20815d382403a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 19:59:29 +0000 Subject: [PATCH 2/3] Fix mass assignment vulnerabilities in blog and job controllers Co-authored-by: Adityavanjre <66417028+Adityavanjre@users.noreply.github.com> From 28ab8502a9c5d876901fef05ae5a651924cd579d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 05:15:49 +0000 Subject: [PATCH 3/3] Fix mass assignment vulnerabilities in blog and job controllers Co-authored-by: Adityavanjre <66417028+Adityavanjre@users.noreply.github.com>