All skills
asyrafhussin avatar

/laravel-best-practices

@ef59186

Laravel 13 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns.

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/laravel-best-practices

This session only. Nothing lands on disk.

rulessec-mass-assignment.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Protect Against Mass Assignment

Impact: HIGH (Prevents security vulnerabilities)

Why It Matters

Mass assignment vulnerabilities allow attackers to modify database fields they shouldn't have access to. A malicious user could set is_admin=1 or role=admin if those fields aren't protected.

Bad Example

// No protection - allows any field to be mass assigned
class User extends Model
{
    protected $guarded = [];  // DANGEROUS!
}

// Attacker can POST: { "email": "test@test.com", "is_admin": true }
User::create($request->all());  // is_admin is set!
// Using $request->all() with fillable
class User extends Model
{
    protected $fillable = ['name', 'email', 'password'];
}

// Still dangerous if you accidentally expand fillable
User::create($request->all());
// Overly permissive fillable
class Post extends Model
{
    protected $fillable = [
        'title',
        'body',
        'user_id',      // Dangerous! User could change author
        'published_at', // Dangerous! User could bypass moderation
    ];
}

Good Example

Use $fillable Restrictively

// Only include user-submittable fields
class Post extends Model
{
    protected $fillable = [
        'title',
        'body',
        'category_id',
    ];
}

// Set sensitive fields explicitly
$post = new Post($request->validated());
$post->user_id = auth()->id();
$post->save();

Use Form Request validated()

// Only use validated data
class PostController extends Controller
{
    public function store(StorePostRequest $request)
    {
        // Only fields from rules() are included
        $post = Post::create($request->validated());
    }
}

// Form Request controls what's allowed
class StorePostRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
            // user_id is NOT here - can't be submitted
        ];
    }
}

Set Sensitive Fields Manually

// Set sensitive fields explicitly
public function store(StorePostRequest $request)
{
    $post = Post::create([
        ...$request->validated(),
        'user_id' => auth()->id(),
        'status' => 'draft',
    ]);
}

// Or use tap
public function store(StorePostRequest $request)
{
    $post = tap(new Post($request->validated()), function ($post) {
        $post->user_id = auth()->id();
        $post->published_at = null;
        $post->save();
    });
}

Different Fillable for Different Actions

class Post extends Model
{
    protected $fillable = [
        'title',
        'body',
        'category_id',
    ];

    // Admin can fill more fields
    public function fillableByAdmin(): array
    {
        return [
            'title',
            'body',
            'category_id',
            'user_id',
            'published_at',
            'featured',
        ];
    }
}

// In admin controller
public function store(AdminStorePostRequest $request)
{
    $post = new Post();
    $post->forceFill($request->validated())->save();
}

Use $guarded for Simple Models

// Guard only the sensitive fields
class Category extends Model
{
    // These fields cannot be mass assigned
    protected $guarded = ['id', 'created_at', 'updated_at'];

    // Everything else is fillable
}

Never Use in Production

// NEVER do this in production
protected $guarded = [];

// NEVER do this
Model::unguard();
Post::create($request->all());
Model::reguard();

Recommended Patterns

Pattern Use Case
$fillable + validated() Most models
$guarded for sensitive fields Simple models with few sensitive fields
Manual assignment Sensitive fields like user_id, role
forceFill() Admin operations with extra validation

Testing for Vulnerabilities

// Test that mass assignment is protected
public function test_cannot_mass_assign_user_id()
{
    $user = User::factory()->create();
    $otherUser = User::factory()->create();

    $this->actingAs($user)
        ->post('/posts', [
            'title' => 'Test',
            'body' => 'Content',
            'user_id' => $otherUser->id,  // Attempting to assign to other user
        ]);

    $post = Post::first();
    $this->assertEquals($user->id, $post->user_id);  // Should be current user
}

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive guide to Laravel 13 best practices, providing safe and standard architectural, database, and security patterns for PHP development. No malicious behavior or security risks were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    1/37 files flagged

  • ZeroLeaks5mo

    2 findings · Score: 80/100

Signed by skilld at ef59186. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
Other metadata
metadata
{
  "author": "Laravel Community",
  "version": "2.1.0",
  "laravelVersion": "13.x",
  "phpVersion": "8.3+"
}

README badge

README badge for asyrafhussin/agent-skills/laravel-best-practices