Description
✏️ Describe the bug
If your application uses mapped property names and the property is not required — meaning it can be omitted(e.g., by being set to null, having a default value, lacking a 'required' validation rule, or being conditionally validated with rules like required_if, sometimes, etc.) — then the validator can be bypassed by using the original property name.
This issue arises because the validation logic only checks the mapped property name. When it determines the property is not required and no value is provided under the mapped name, it skips further validation rules.
However, during assignment, the property can still be set using either the mapped name or the original name. This inconsistency between validation (which only looks at the mapped name) and assignment (which accepts both) creates a loophole where validation is bypassed but the property still gets assigned — potentially with invalid or unsafe data.
↪️ To Reproduce
Provide us a pest test like this one which shows the problem:
class Page extends BaseData
{
#[Min(1)]
#[MapInputName('page.number')]
public int $number = 1;
#[Between(1, 200)]
#[MapInputName('page.size')]
public int $size = 10;
public static function prepareForPipeline(array $properties): array
{
// unset($properties['size'], $properties['number']);
return $properties;
}
}
it('bypasses validator using original attribute name', function () {
// no error
$page = Page::validateAndCreate([
'size' => 300,
]);
// 300
dd($page->size);
});
✅ Expected behavior
print 10(Do not use the original property name)
or
Illuminate\Validation\ValidationException: The page.size field must be between 1 and 200.(Keep the original property name)
🖥️ Versions
Laravel: 11.44.1
Laravel Data: 4.13.2
PHP: 8.2.20
Confusion Around Mapping Property Names
If a property has a map setting, can its original property name still be used?
If so, it feels more like an alias rather than a strict mapping.
Do not use the original property name
However, this conflicts with the following test case:
Keep the original property name
But this also conflicts with the following test case:
Related link
https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/mapping-property-names