Skip to content

Commit 21d8632

Browse files
Fix Guard bypass in Eloquent models in laravel/framework
1 parent 1e87181 commit 21d8632

File tree

5 files changed

+481
-2
lines changed

5 files changed

+481
-2
lines changed

composer.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,10 @@
125125
"Illuminate\\Support\\": "overrides/laravel/framework/src/Illuminate/Support/",
126126
"Illuminate\\Http\\": "overrides/laravel/framework/src/Illuminate/Http/",
127127
"Illuminate\\Database\\Eloquent\\": "overrides/laravel/framework/src/Illuminate/Database/Eloquent/",
128+
"Illuminate\\Database\\Eloquent\\Concerns\\": "overrides/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/",
128129
"Illuminate\\Pagination\\": "overrides/laravel/framework/src/Illuminate/Pagination/",
129130
"Illuminate\\Session\\": "overrides/laravel/framework/src/Illuminate/Session/",
131+
"Illuminate\\Queue\\": "overrides/laravel/framework/src/Illuminate/Queue/",
130132
"Carbon\\": "overrides/nesbot/carbon/src/Carbon/",
131133
"Illuminate\\Cache\\": "overrides/laravel/framework/src/Illuminate/Cache/",
132134
"Illuminate\\Config\\": "overrides/laravel/framework/src/Illuminate/Config/",
@@ -220,11 +222,13 @@
220222
"vendor/symfony/http-foundation/FileBag.php",
221223
"vendor/symfony/http-foundation/Request.php",
222224
"vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
225+
"vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php",
223226
"vendor/laravel/framework/src/Illuminate/Pagination/AbstractPaginator.php",
224227
"vendor/laravel/framework/src/Illuminate/Pagination/Paginator.php",
225228
"vendor/laravel/framework/src/Illuminate/Pagination/LengthAwarePaginator.php",
226229
"vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php",
227230
"vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php",
231+
"vendor/laravel/framework/src/Illuminate/Queue/Listener.php",
228232
"vendor/nesbot/carbon/src/Carbon/Carbon.php",
229233
"vendor/laravel/framework/src/Illuminate/Cache/Repository.php",
230234
"vendor/laravel/framework/src/Illuminate/Config/Repository.php",
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
<?php
2+
3+
namespace Illuminate\Database\Eloquent\Concerns;
4+
5+
use Illuminate\Support\Str;
6+
7+
trait GuardsAttributes
8+
{
9+
/**
10+
* The attributes that are mass assignable.
11+
*
12+
* @var array
13+
*/
14+
protected $fillable = [];
15+
16+
/**
17+
* The attributes that aren't mass assignable.
18+
*
19+
* @var array
20+
*/
21+
protected $guarded = ['*'];
22+
23+
/**
24+
* Indicates if all mass assignment is enabled.
25+
*
26+
* @var bool
27+
*/
28+
protected static $unguarded = false;
29+
30+
/**
31+
* The actual columns that exist on the database and can be guarded.
32+
*
33+
* @var array
34+
*/
35+
protected static $guardableColumns = [];
36+
37+
/**
38+
* Get the fillable attributes for the model.
39+
*
40+
* @return array
41+
*/
42+
public function getFillable()
43+
{
44+
return $this->fillable;
45+
}
46+
47+
/**
48+
* Set the fillable attributes for the model.
49+
*
50+
* @param array $fillable
51+
* @return $this
52+
*/
53+
public function fillable(array $fillable)
54+
{
55+
$this->fillable = $fillable;
56+
57+
return $this;
58+
}
59+
60+
/**
61+
* Get the guarded attributes for the model.
62+
*
63+
* @return array
64+
*/
65+
public function getGuarded()
66+
{
67+
return $this->guarded;
68+
}
69+
70+
/**
71+
* Set the guarded attributes for the model.
72+
*
73+
* @param array $guarded
74+
* @return $this
75+
*/
76+
public function guard(array $guarded)
77+
{
78+
$this->guarded = $guarded;
79+
80+
return $this;
81+
}
82+
83+
/**
84+
* Disable all mass assignable restrictions.
85+
*
86+
* @param bool $state
87+
* @return void
88+
*/
89+
public static function unguard($state = true)
90+
{
91+
static::$unguarded = $state;
92+
}
93+
94+
/**
95+
* Enable the mass assignment restrictions.
96+
*
97+
* @return void
98+
*/
99+
public static function reguard()
100+
{
101+
static::$unguarded = false;
102+
}
103+
104+
/**
105+
* Determine if current state is "unguarded".
106+
*
107+
* @return bool
108+
*/
109+
public static function isUnguarded()
110+
{
111+
return static::$unguarded;
112+
}
113+
114+
/**
115+
* Run the given callable while being unguarded.
116+
*
117+
* @param callable $callback
118+
* @return mixed
119+
*/
120+
public static function unguarded(callable $callback)
121+
{
122+
if (static::$unguarded) {
123+
return $callback();
124+
}
125+
126+
static::unguard();
127+
128+
try {
129+
return $callback();
130+
} finally {
131+
static::reguard();
132+
}
133+
}
134+
135+
/**
136+
* Determine if the given attribute may be mass assigned.
137+
*
138+
* @param string $key
139+
* @return bool
140+
*/
141+
public function isFillable($key)
142+
{
143+
if (static::$unguarded) {
144+
return true;
145+
}
146+
147+
// If the key is in the "fillable" array, we can of course assume that it's
148+
// a fillable attribute. Otherwise, we will check the guarded array when
149+
// we need to determine if the attribute is black-listed on the model.
150+
if (in_array($key, $this->getFillable())) {
151+
return true;
152+
}
153+
154+
// If the attribute is explicitly listed in the "guarded" array then we can
155+
// return false immediately. This means this attribute is definitely not
156+
// fillable and there is no point in going any further in this method.
157+
if ($this->isGuarded($key)) {
158+
return false;
159+
}
160+
161+
return empty($this->getFillable()) &&
162+
strpos($key, '.') === false &&
163+
! Str::startsWith($key, '_');
164+
}
165+
166+
/**
167+
* Determine if the given key is guarded.
168+
*
169+
* @param string $key
170+
* @return bool
171+
*/
172+
public function isGuarded($key)
173+
{
174+
//return in_array($key, $this->getGuarded()) || $this->getGuarded() == ['*'];
175+
176+
if (empty($this->getGuarded())) {
177+
return false;
178+
}
179+
180+
return $this->getGuarded() == ['*'] ||
181+
! empty(preg_grep('/^'.preg_quote($key).'$/i', $this->getGuarded())) ||
182+
! $this->isGuardableColumn($key);
183+
}
184+
185+
/**
186+
* Determine if the given column is a valid, guardable column.
187+
*
188+
* @param string $key
189+
* @return bool
190+
*/
191+
protected function isGuardableColumn($key)
192+
{
193+
if (! isset(static::$guardableColumns[get_class($this)])) {
194+
static::$guardableColumns[get_class($this)] = $this->getConnection()
195+
->getSchemaBuilder()
196+
->getColumnListing($this->getTable());
197+
}
198+
199+
return in_array($key, static::$guardableColumns[get_class($this)]);
200+
}
201+
202+
/**
203+
* Determine if the model is totally guarded.
204+
*
205+
* @return bool
206+
*/
207+
public function totallyGuarded()
208+
{
209+
return count($this->getFillable()) == 0 && $this->getGuarded() == ['*'];
210+
}
211+
212+
/**
213+
* Get the fillable attributes of a given array.
214+
*
215+
* @param array $attributes
216+
* @return array
217+
*/
218+
protected function fillableFromArray(array $attributes)
219+
{
220+
if (count($this->getFillable()) > 0 && ! static::$unguarded) {
221+
return array_intersect_key($attributes, array_flip($this->getFillable()));
222+
}
223+
224+
return $attributes;
225+
}
226+
}

overrides/laravel/framework/src/Illuminate/Database/Eloquent/Model.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@ public function qualifyColumn($column)
272272
*/
273273
protected function removeTableFromKey($key)
274274
{
275-
return Str::contains($key, '.') ? last(explode('.', $key)) : $key;
275+
//return Str::contains($key, '.') ? last(explode('.', $key)) : $key;
276+
return $key;
276277
}
277278

278279
/**

0 commit comments

Comments
 (0)