Laravel Validation Rule Injection

October 12, 2020

What is a Laravel Validation Rule Injection? Well first let's look at the following vulnerable code

public function update(Request $request) {
 $id = $request->route('id');
 $rules = [
   'username' => 'required|unique:users,username,' . $id,
 ];

 $validator = Validator::make($request->post(), $rules);
 if ($validator->fails()) {
   return response()->json($validator->errors(), 422);
 }

 $user = User::findOrFail($id);
 $user->fill($validator->validated());
 $user->save();
 return response()->json(['user' => $user]);
}

If your eye caught the vulnerability in

'required|unique:users,username,' . $id code

great job!

So what the “unique” rule is doing here, it’s making sure the username is unique inside the users table and it will also ignore the row with the given ID during the check. But the issue here is that we got the $id from the request and without validating it, we used it to create a validation rule based on the user’s input. So using that we can customize the validation rule and create some attack vectors, let's look at the following examples.

1. Making the validation rule optional

The simplest thing that we can do here is to send a request with ID = 10|sometimes, which will alter the validation rule to required|unique:users,username,10|sometimes and will allow us to not skip the username in the request data, depending on your application business logic, a bypass like this might create a security issue.

2. DDOS the server by creating an evil REGEX validation rule

Another attack vector here could be to create an evil Regex validation, that is vulnerable to ReDoS attack and DDOS the app.

For example, the following request would consume a lot of CPU and if multiple requests sent concurrently can cause a big CPU spike on the server.

PUT /api/users/1,id,name,444|regex:%23(.*a){100}%23
{
    "username": "aaaaa__ALOT_OF_REPETED_As_aaaaaaaaaa"
}

3. SQL Injection

The simplest SQL injection here would be to just add an extra validation rule that is querying the database, for example

PUT /api/users/1,id,name,444|unique:users,secret_col_name_here
{
    "username":  "secret_value_to_check"
}

But important to mention since using unique we are able to provide both custom column name and values (values are not going through PDO parameter binding) possibilities of SQL injection here could be not limited to just a simple attack vector that is mentioned above. For more details, check out Laravel Blog’s post here.

Prevention tips:

  • The best prevention here is to not use user-provided data to create a validation rule
  • If you have to build your validation rule based on provided data(ID in our example), make sure to cast or validate the provided value before putting it into the validation rule.

📝 If you have a Laravel application that is running on production, check out also our Laravel applications security testing service.

Contact us today
for a free consultation.
Do not delay when it comes to security.
Contact us today for a free consultation.
    Thanks for contacting us!
    We will be in touch with you shortly.