Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
SecurityJune 21, 20265 min read

Preventing Mass Assignment Vulnerabilities with DTOs in Laravel and Express

Stop mass assignment vulnerabilities by using DTOs to decouple input from your database. Learn how to secure your Laravel and Express apps with strict validation.

mass assignmentDTOinput validationsecure codingweb application securityLaravelExpressSecurityWebBackend
Close-up of Scrabble tiles spelling 'data breach' on a blurred background

I remember the first time I realized a user had updated their own is_admin flag via a simple API request. I’d sent the entire request body directly into an Eloquent update() method, thinking I was being efficient. That "shortcut" took me roughly four hours to roll back and audit, and it taught me that convenience is often the enemy of security.

Mass assignment happens when an application takes user input and blindly maps it to an internal model or database record. When you don't explicitly whitelist what fields can be updated, you’re effectively handing the keys to your database over to whoever hits your endpoint.

Understanding Mass Assignment Risks

In both Laravel and Express, the temptation to pass req.body or $request->all() into a model is high. It’s fast, it makes controllers look clean, and it works perfectly—until it doesn't.

If your user model has an is_admin or account_balance column, and your registration or profile update endpoint accepts all incoming parameters, an attacker can simply inject those keys into their JSON payload. Even if the field isn't in your frontend form, a quick look at the network tab or a simple curl command reveals the underlying schema.

We've explored preventing IDOR vulnerabilities in Laravel with attribute-based access control before, but mass assignment is a different beast. It’s not about accessing someone else's data; it’s about tricking your application into changing data it shouldn't be touching.

Solving Mass Assignment with DTOs

Unrecognizable smart male student with pen  taking notes while solving equations at table during lesson in classroom on blurred background

The most effective way to stop this is to stop passing raw request objects into your persistence layer. Instead, use Data Transfer Objects (DTOs). A DTO is a simple object that carries data between processes. By defining exactly which fields are allowed, you create a "contract" for your data.

Implementation in Laravel

Laravel provides $fillable arrays on models, which is a good first line of defense. However, relying solely on model properties can be brittle. I prefer using Form Requests to handle the validation and transformation.

PHP
#6A9955">// app/Http/Requests/UpdateUserRequest.php
public function rules(): array
{
    return [
        'name' => 'required|string|max:255',
        'email' => 'required|email',
        #6A9955">// 'is_admin' is intentionally omitted here
    ];
}

#6A9955">// In your controller
public function update(UpdateUserRequest $request, User $user)
{
    #6A9955">// Only validated data is returned
    $user->update($request->validated());
}

By calling validated(), you ensure that even if a malicious user sends a payload containing is_admin: true, the framework discards it before it ever reaches your database query.

Implementation in Express

In the Node.js ecosystem, especially with Mongoose or Sequelize, the risk is often higher because JavaScript objects are so flexible. We first tried using simple middleware to strip keys, but it was error-prone and easy to forget. We now use Zod for schema validation to enforce strict DTOs.

JAVASCRIPT
const userSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

app.patch(CE9178">'/profile', (req, res) => {
  const result = userSchema.safeParse(req.body);
  
  if (!result.success) {
    return res.status(400).json(result.error);
  }

  // Only use result.data, never req.body
  db.users.update(userId, result.data);
});

This approach forces you to explicitly define the "shape" of the data. If you don't include a field in your Zod schema, it simply doesn't exist for the rest of your application logic.

Why This Works

The secret isn't just "better validation"—it's about separation of concerns. Your database model should represent your storage layer, while your DTO represents your application's intent.

When you confuse the two, you open yourself up to preventing SQL injection in modern frameworks issues if your validation logic is bypassed or if you're dynamically building queries. DTOs act as a buffer. They ensure that even if your database schema grows, your public API remains locked down.

Common Pitfalls

  1. Partial Updates: If you need to allow some fields but not others, don't try to reuse the same DTO. Create a CreateUserDTO and an UpdateUserDTO. It feels like extra boilerplate, but it's much safer than trying to make one DTO fit every scenario.
  2. Nested Objects: If your payload contains nested objects (like addresses), validate the nested structure strictly. Don't just validate the parent object.
  3. Implicit Trust: Never trust the client, even if it's your own frontend. A DTO doesn't care who sent the data; it only cares that the data conforms to the expected structure.

FAQ

Q: Is $fillable in Laravel enough? A: It’s a great start, but it’s a global setting for the model. DTOs or Form Requests provide context-specific security, which is much safer when you have different endpoints requiring different levels of access.

Q: Does this add too much overhead? A: It adds a few lines of code per endpoint. Compared to the time spent on a security audit or patching a data breach, it’s an investment that pays for itself in about 20 minutes of development time.

Q: What if I need to update a field that isn't in the DTO? A: Then you create a specific method or a separate DTO for that action. It forces you to think about the security implications of that specific update rather than just "opening" the field to the world.

I still sometimes find myself wanting to grab the whole req.body object during rapid prototyping. It's a hard habit to break. But every time I catch myself reaching for that shortcut, I remind myself that the cost of being "fast" is often the cost of my users' trust. Keep your boundaries strict, and your data will stay where it belongs.

Back to Blog

Similar Posts

A close-up of a padlock securing a wire fence, symbolizing protection and safety.
SecurityJune 21, 20264 min read

Preventing IDOR vulnerabilities in Laravel with attribute-based access control

Prevent IDOR vulnerabilities in your Laravel apps by using attribute-based access control in Eloquent models. Secure your data with clean, automated logic.

Read more
A close-up of CDs and disks on a desk, featuring hands in a tech environment.
Security
June 21, 2026
4 min read

Secure file uploads from the ground up: A developer's guide

Secure file uploads from the ground up require more than basic validation. Learn how to prevent RCE and directory traversal in your production systems.

Read more
Close-up of colorful programming code displayed on a computer screen, showcasing modern coding concepts.
SecurityJune 20, 20264 min read

XSS prevention strategies: A guide for modern web developers

XSS prevention strategies are essential for securing modern web apps. Learn to identify the three main variants and implement robust, layered defenses today.

Read more