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. Detects SQL injection, XSS, SSRF, shell injection, path traversal, and open redirects by tracking user input through Laravel code without running it.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Steps
1. **Installation**:
   ```bash
   composer config minimum-stability dev
   composer require --dev psalm/plugin-laravel:^4.8
  1. Initialize Laravel-tailored config:

    ./vendor/bin/psalm-laravel init --level 4
    

    (Start with --level 4 for a balanced strictness; adjust later.)

  2. First analysis:

    ./vendor/bin/psalm-laravel analyze
    

    (Security taint analysis runs automatically—no extra flags needed.)

  3. Baseline existing issues (for legacy projects):

    ./vendor/bin/psalm --set-baseline=psalm-baseline.xml
    

Where to Look First

  • Security issues: Focus on TaintedSql, TaintedXss, and TaintedShell errors in psalm.xml output.
  • Type issues: Prioritize MissingReturnType, MixedAssignment, and UndefinedClass in Laravel-specific code (e.g., facades, Eloquent).
  • Quick wins: Run ./vendor/bin/psalm-laravel analyze --stats to identify the most common issue types.

First Use Case

Catch SQL injection in a controller:

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

Fix: Validate/sanitize $column or use a whitelist:

$allowedColumns = ['name', 'created_at'];
$column = in_array($request->input('sort'), $allowedColumns)
    ? $request->input('sort')
    : 'name';

New Use Case: DateTimeInterface Support in whereDate()

// Previously would trigger ImplicitToStringCast error
Post::query()->whereDate('created_at', CarbonImmutable::now()); // Now works!

Implementation Patterns

Core Workflows

  1. Daily Security Scan:

    ./vendor/bin/psalm-laravel analyze --output-format=text --report=security.sarif
    
    • Integrate security.sarif into GitHub Security tab (requires GHAS for private repos).
    • Use --threads=4 for faster analysis on CI (GitHub Actions defaults to 1 thread).
  2. CI Integration (GitHub Actions):

    # .github/workflows/psalm.yml
    jobs:
      psalm:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: shivammathur/setup-php@v2
            with:
              php-version: '8.3'
              extensions: igbinary
          - run: composer install --prefer-dist
          - run: ./vendor/bin/psalm --output-format=github --threads=4
    
    • Pro tip: Add git-restore-mtime-action to preserve file timestamps for Psalm cache:
      - uses: chetan/git-restore-mtime-action@v2
      
  3. Incremental Adoption:

    • Start with --level 4 (default) and gradually lower to 1 (strictest).
    • Use --ignore-errors to suppress specific issues temporarily:
      ./vendor/bin/psalm --ignore-errors=MissingReturnType --ignore-errors=TaintedSql
      

Integration Tips

  • Laravel Facades: Psalm auto-generates stubs for facades (e.g., Route::, Cache::). No manual @mixin needed.
  • Eloquent Models: Schema inference from php artisan schema:dump or migrations. Ensure:
    // config/psalm.php
    'schema_dumps' => [
        database_path('schema_dump.sql'),
    ],
    
  • Custom Taint Sources/Sinks: Extend via psalm.xml:
    <psalm>
      <plugins>
        <pluginClass class="Psalm\LaravelPlugin\Plugin">
          <param name="custom_taint_sources">
            <array>
              <string>App\Services\UntrustedInput::get()</string>
            </array>
          </param>
        </pluginClass>
      </plugins>
    </psalm>
    

Common Patterns

Pattern Example
Taint Propagation User input → Helper → Controller → Query → Psalm flags TaintedSql.
Facade Type Safety Route::get() returns Illuminate\Routing\Route (not mixed).
Collection Methods Collection::where() infers return type based on model properties.
Middleware Checks Psalm validates Handle method signatures in middleware.
DateTimeInterface whereDate() now accepts CarbonImmutable/DateTimeImmutable in two-arg form.

Gotchas and Tips

Pitfalls

  1. False Positives in Taint Analysis:

    • Issue: Psalm flags validated input as tainted.
    • Fix: Use @psalm-suppress Tainted* or annotate validation:
      /** @psalm-suppress TaintedSql */
      $column = $request->validate(['sort' => 'string|in:name,created_at'])->input('sort');
      
    • Alternative: Whitelist sinks in psalm.xml:
      <psalm>
        <plugins>
          <pluginClass class="Psalm\LaravelPlugin\Plugin">
            <param name="allowed_tainted_sinks">
              <array>
                <string>App\Models\User::where()</string>
              </array>
            </param>
          </pluginClass>
        </plugins>
      </psalm>
      
  2. Schema Inference Failures:

    • Issue: Psalm doesn’t recognize model columns.
    • Fix:
      • Run php artisan schema:dump and update psalm.xml:
        <psalm>
          <schema_dumps>
            <file>database/schema_dump.sql</file>
          </schema_dumps>
        </psalm>
        
      • Manually annotate models:
        /** @property string $name */
        class User extends Model {}
        
  3. CI Cache Invalidation:

    • Issue: Psalm cache fails on GitHub Actions.
    • Fix: Restore file timestamps:
      - uses: chetan/git-restore-mtime-action@v2
      
    • Key: Cache depends on psalm.xml, psalm-baseline.xml, and composer.lock.
  4. Performance on Large Codebases:

    • Issue: Analysis takes >5 minutes.
    • Fix:
      • Use --threads=8 (adjust based on CI runner cores).
      • Exclude directories:
        <psalm>
          <projectFiles>
            <exclude-name>tests/**</exclude-name>
            <exclude-name>vendor/**</exclude-name>
          </projectFiles>
        </psalm>
        

Debugging Tips

  • Inspect Taint Flow:

    ./vendor/bin/psalm --taint-analysis --taint-flow=debug
    

    (Shows how data propagates between sources/sinks.)

  • Verify Facade Stubs:

    ./vendor/bin/psalm --generate-stubs --output-dir=stubs
    

    (Check stubs/Illuminate/Foundation/Application.php for generated aliases.)

  • Isolate Issues:

    ./vendor/bin/psalm --ignore-errors=* --show-info=true
    

    (Lists all issues with file/line context.)

Extension Points

  1. Custom Checks:

    • Add Laravel-specific rules in psalm.xml:
      <psalm>
        <file_list>
          <file>app/Rules/CustomRule.php</file>
        </file_list>
      </psalm>
      
    • Example: Enforce authorize() in controllers:
      // app/Rules/AuthorizeRule.php
      class AuthorizeRule extends CustomRule {
          public function apply(Call $call): void {
              if ($call->getFunction()->getName() === 'get' &&
                  !$call->getParentClass()?->isSubclassOf('Illuminate\Routing\Controller')) {
                  $this->reportError('Controllers must use authorize().');
              }
          }
      }
      
  2. Override Taint Behavior:

    • Extend Psalm\LaravelPlugin\Plugin to add custom sources/sinks:
      // app/Plugins/CustomTaintPlugin.php
      use Psalm\Plugin\PluginEntryPointInterface;
      
      class CustomTaintPlugin implements PluginEntryPointInterface {
          public function getPluginName(): string { return 'custom_taint'; }
          public function register(ContainerInterface $container): void {
              $container->getDefinition
      
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle