VYPR
High severityNVD Advisory· Published Sep 4, 2020· Updated Aug 4, 2024

CVE-2020-24941

CVE-2020-24941

Description

An issue was discovered in Laravel before 6.18.35 and 7.x before 7.24.0. The $guarded property is mishandled in some situations involving requests with JSON column nesting expressions.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Laravel JSON column nesting expressions bypass $guarded mass assignment protection, allowing unintended model updates.

Vulnerability

Overview

CVE-2020-24941 is a mass assignment vulnerability in Laravel versions before 6.18.35 and 7.x before 7.24.0. The root cause lies in the mishandling of the $guarded property when processing requests that include JSON column nesting expressions, such as {"foo->bar": "value"}. The framework fails to properly validate whether the column specified in the nested expression is a genuine database column, allowing attackers to bypass the intended guard logic.

Exploitation

Method

An attacker can exploit this vulnerability by crafting a request that includes a JSON nesting expression targeting a specific key within a JSON column. For example, even if the JSON column foo is listed in the $guarded array, the expression foo->bar is not matched because the guard check did not recognize the -> syntax as a reference to the parent column [1]. The patch resolves this by retrieving the actual column listing from the database and verifying that the column being updated exists in that list [1][3].

Impact

Successful exploitation allows an attacker to perform mass assignment updates on guarded JSON column keys, potentially modifying sensitive data that was intended to be protected. The impact is limited to models using the $guarded property with a list of specific columns; models using $fillable, an empty $guarded, or $guarded = ['*'] are not affected [3].

Mitigation

Laravel addressed the issue in versions 6.18.35 and 7.24.0. The fix introduces an additional database query to fetch the column listing only when $guarded contains specific column names. Users are strongly advised to upgrade to patched versions or migrate to using $fillable for mass assignment protection [3].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
laravel/frameworkPackagist
< 6.18.356.18.35
laravel/frameworkPackagist
>= 7.0.0, < 7.24.07.24.0

Affected products

3

Patches

1
897d10777573

[6.x] Verify column names are actual columns when using guarded (#33777)

https://github.com/laravel/frameworkTaylor OtwellAug 7, 2020via ghsa
2 files changed · +40 4
  • src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php+28 3 modified
    @@ -27,6 +27,13 @@ trait GuardsAttributes
          */
         protected static $unguarded = false;
     
    +    /**
    +     * The actual columns that exist on the database and can be guarded.
    +     *
    +     * @var array
    +     */
    +    protected static $guardableColumns = [];
    +
         /**
          * Get the fillable attributes for the model.
          *
    @@ -164,12 +171,30 @@ public function isFillable($key)
          */
         public function isGuarded($key)
         {
    -        if (strpos($key, '->') !== false) {
    -            $key = Str::before($key, '->');
    +        if (empty($this->getGuarded())) {
    +            return false;
             }
     
             return $this->getGuarded() == ['*'] ||
    -               ! empty(preg_grep('/^'.preg_quote($key).'$/i', $this->getGuarded()));
    +               ! empty(preg_grep('/^'.preg_quote($key).'$/i', $this->getGuarded())) ||
    +               ! $this->isGuardableColumn($key);
    +    }
    +
    +    /**
    +     * Determine if the given column is a valid, guardable column.
    +     *
    +     * @param  string  $key
    +     * @return bool
    +     */
    +    protected function isGuardableColumn($key)
    +    {
    +        if (! isset(static::$guardableColumns[get_class($this)])) {
    +            static::$guardableColumns[get_class($this)] = $this->getConnection()
    +                        ->getSchemaBuilder()
    +                        ->getColumnListing($this->getTable());
    +        }
    +
    +        return in_array($key, static::$guardableColumns[get_class($this)]);
         }
     
         /**
    
  • tests/Database/DatabaseEloquentModelTest.php+12 1 modified
    @@ -10,6 +10,7 @@
     use Illuminate\Contracts\Events\Dispatcher;
     use Illuminate\Database\Connection;
     use Illuminate\Database\ConnectionResolverInterface;
    +use Illuminate\Database\ConnectionResolverInterface as Resolver;
     use Illuminate\Database\Eloquent\Builder;
     use Illuminate\Database\Eloquent\Collection;
     use Illuminate\Database\Eloquent\JsonEncodingException;
    @@ -1014,11 +1015,21 @@ public function testUnderscorePropertiesAreNotFilled()
         public function testGuarded()
         {
             $model = new EloquentModelStub;
    +
    +        EloquentModelStub::setConnectionResolver($resolver = m::mock(Resolver::class));
    +        $resolver->shouldReceive('connection')->andReturn($connection = m::mock(stdClass::class));
    +        $connection->shouldReceive('getSchemaBuilder->getColumnListing')->andReturn(['name', 'age', 'foo']);
    +
             $model->guard(['name', 'age']);
             $model->fill(['name' => 'foo', 'age' => 'bar', 'foo' => 'bar']);
             $this->assertFalse(isset($model->name));
             $this->assertFalse(isset($model->age));
             $this->assertSame('bar', $model->foo);
    +
    +        $model = new EloquentModelStub;
    +        $model->guard(['name', 'age']);
    +        $model->fill(['Foo' => 'bar']);
    +        $this->assertFalse(isset($model->Foo));
         }
     
         public function testFillableOverridesGuarded()
    @@ -2134,7 +2145,7 @@ public function getDates()
     class EloquentModelSaveStub extends Model
     {
         protected $table = 'save_stub';
    -    protected $guarded = ['id'];
    +    protected $guarded = [];
     
         public function save(array $options = [])
         {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.