Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Plugin Laravel Laravel Package

psalm/plugin-laravel

Laravel Psalm plugin for deep static analysis plus taint-based security scanning. Detect SQL injection, XSS, SSRF, shell injection, path traversal, and open redirects by tracking user input through Laravel code—without executing it. Complements Larastan/PHPStan.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the plugin (ensure composer.json allows dev/beta packages):
    composer config minimum-stability dev && composer require --dev psalm/plugin-laravel:^4.8
    
  2. Generate Laravel-optimized psalm.xml (default strictness level 4):
    ./vendor/bin/psalm-laravel init
    
  3. Run analysis (security checks included by default):
    ./vendor/bin/psalm-laravel analyze
    
    For CI/CD: Use the one-liner to auto-generate GitHub Actions:
    ./vendor/bin/psalm-laravel add github
    

First Use Case: Security Scanning

Analyze a vulnerable route (e.g., SQL injection via user input):

// app/Http/Controllers/SearchController.php
Route::get('/search', function (Request $request) {
    $sortBy = $request->input('sort'); // Tainted source
    User::where('name', 'John')->orderBy($sortBy)->get(); // Psalm flags tainted SQL
});

Expected Output:

ERROR TaintedSql: Detected tainted SQL in SearchController.php:12

Implementation Patterns

Core Workflows

  1. Type-Centric Development

    • Facade Resolution: The plugin auto-generates stubs for Laravel facades (e.g., Auth::user()User|null). Use Auth::guard('admin')->user() for narrowed types.
    • Eloquent Narrowing: Leverage dynamic where{Column} (e.g., User::whereName()) with type-safe arguments:
      User::whereName('John')->get(); // Psalm infers `Collection<User>`
      
  2. Security-Integrated CI

    • Baseline Management: Suppress legacy issues with:
      ./vendor/bin/psalm --set-baseline=psalm-baseline.xml
      
    • Strict Mode: Gradually tighten errorLevel (e.g., 1 for strictest) in psalm.xml:
      <errorLevel>1</errorLevel>
      
  3. Custom Checks

    • Extend with Laravel-specific rules (e.g., ModelPropertyHandler for SET columns):
      <fileList>
          <directory name="app/Models" />
      </fileList>
      <plugins>
          <pluginClass name="Psalm\Plugin\Laravel\Plugin" />
      </plugins>
      

Integration Tips

  • Testbench Support: Run on packages with:
    ./vendor/bin/psalm-laravel analyze --testbench
    
  • Macroable Types: Recover macro return types from docblocks (e.g., Collection::macro('sum', fn() => ...)).
  • Carbon Narrowing: Use cascading methods with type hints:
    Carbon::parse($date)->startOfDay(); // Psalm narrows to `Carbon`
    

Gotchas and Tips

Pitfalls

  1. False Positives in Taint Analysis

    • Issue: Js::from()/Js::encode() may flag legitimate uses.
    • Fix: Specialize taint per call-site (v4.12.0+):
      Js::from($request->input('safe_data'))->encode(); // No false alarm
      
  2. Facade Resolution Gaps

    • Issue: Custom facades in package repos may not resolve.
    • Fix: Use --testbench flag or manually add stubs to psalm.xml:
      <stubFiles>
          <directory name="vendor/package/src/Stubs" />
      </stubFiles>
      
  3. Dynamic where{Column} Overhead

    • Issue: Multi-segment calls (e.g., User::whereHas('posts.wherePublished')) may fail.
    • Fix: Validate segments explicitly:
      User::whereHas('posts', fn($q) => $q->wherePublished(true));
      

Debugging

  • Diagnose Command: Inspect runtime behavior:
    ./vendor/bin/psalm-laravel diagnose
    
  • Config Quirks:
    • Disable resolveConfigReturnTypes if config() narrowing is too strict:
      <param name="resolveConfigReturnTypes" type="bool">false</param>
      

Extension Points

  1. Custom Taint Sources/Sinks Add stubs for unsupported methods (e.g., File::put()):

    // stubs/laravel/Storage.php
    namespace Illuminate\Support\Facades;
    class Storage {
        #[TaintSource]
        public function put(string $path, string $contents) { ... }
    }
    
  2. Eloquent Attribute Handling Override ModelPropertyHandler for custom attributes:

    // app/Providers/AppServiceProvider.php
    Psalm\Plugin\Laravel\Plugin::addModelPropertyHandler(
        \App\Models\User::class,
        fn($model, $property) => match($property) {
            'full_name' => 'string',
            default => null,
        }
    );
    
  3. CI Optimization Cache Psalm storage between runs (.psalm-cache):

    # .github/workflows/psalm.yml
    jobs:
      psalm:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - run: composer install
          - run: ./vendor/bin/psalm-laravel analyze --no-cache
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core