PHPackages                             psalm/plugin-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. psalm/plugin-laravel

ActivePsalm-plugin[Security](/categories/security)

psalm/plugin-laravel
====================

Psalm plugin for Laravel

v4.15.3(3w ago)3345.4M—9.4%79[5 issues](https://github.com/psalm/psalm-plugin-laravel/issues)[1 PRs](https://github.com/psalm/psalm-plugin-laravel/pulls)20MITPHPPHP ^8.2CI passing

Since Feb 18Pushed 2w ago8 watchersCompare

[ Source](https://github.com/psalm/psalm-plugin-laravel)[ Packagist](https://packagist.org/packages/psalm/plugin-laravel)[ Docs](https://github.com/psalm/psalm-plugin-laravel)[ GitHub Sponsors](https://github.com/alies-dev)[ RSS](/packages/psalm-plugin-laravel/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (10)Dependencies (170)Versions (282)Used By (20)

Laravel Psalm Plugin
====================

[](#laravel-psalm-plugin)

[![Packagist version](https://camo.githubusercontent.com/cdd0aa342205390ac15be04e46b28580ca0c1de54d94cbf3de263c141cc5064a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7073616c6d2f706c7567696e2d6c61726176656c2e737667)](https://packagist.org/packages/psalm/plugin-laravel)[![Packagist downloads](https://camo.githubusercontent.com/b914002156b062f954231019fda1b2f42544bbd572ca9826d5790ac5fdef1b88/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7073616c6d2f706c7567696e2d6c61726176656c2e737667)](https://packagist.org/packages/psalm/plugin-laravel)[![Type coverage](https://camo.githubusercontent.com/fb93d70a6dc74873a2936fa8bda61ddf40daaeccbc41eaf47fdced84998bc9f8/68747470733a2f2f73686570686572642e6465762f6769746875622f7073616c6d2f7073616c6d2d706c7567696e2d6c61726176656c2f636f7665726167652e737667)](https://shepherd.dev/github/psalm/psalm-plugin-laravel)[![Tests](https://github.com/psalm/psalm-plugin-laravel/actions/workflows/tests.yml/badge.svg)](https://github.com/psalm/psalm-plugin-laravel/actions/workflows/tests.yml)

Laravel static analysis with built-in security scanning.

The only free tool that combines deep Laravel static analysis with taint-based vulnerability detection that traces user input from request to sink: SQL injection, XSS, shell injection, file traversal, SSRF, open redirects, and timing-unsafe secret comparisons. Everything runs inside your project and your CI. No account, no cloud upload, no code leaves your machine.

```
$sortBy = $request->input('sort');      // tainted source: user input

User::query()->orderBy($sortBy)->get(); // tainted sink: reaches a column name
```

 [![Psalm reporting a tainted SQL finding, tracing $sortBy from Request::input() into orderBy()](https://raw.githubusercontent.com/psalm/psalm-plugin-laravel/master/docs/assets/screenshot-taint.png)](https://raw.githubusercontent.com/psalm/psalm-plugin-laravel/master/docs/assets/screenshot-taint.png)

Real output on a fresh Laravel app, tracing the two lines above from source to sink.

Note

Already using Larastan? psalm-laravel **complements** it with security analysis that PHPStan cannot provide. See [the comparison](#psalm-laravel-or-larastan) below.

Install
-------

[](#install)

```
composer config minimum-stability dev && composer config prefer-stable true
composer require --dev psalm/plugin-laravel:^4.15
./vendor/bin/psalm-laravel init
./vendor/bin/psalm-laravel analyze
```

Requires PHP 8.2+ and Laravel 12 or 13. Full matrix under [Versions &amp; Dependencies](#versions--dependencies).

- [Psalm 7.x](https://github.com/vimeo/psalm/releases) is currently in beta, which is the only reason dev stability is needed. `prefer-stable true` keeps every other package in your project on stable releases, so Psalm itself is the single beta you pull in.
- Want zero beta packages? The 3.x line runs on stable Psalm 6 and needs no stability flags at all: `composer require --dev psalm/plugin-laravel:^3`. It carries the same security checks, and additionally supports Laravel 11.
- `init` writes a `psalm.xml` at the project root with the plugin enabled, `errorLevel="4"` by default (`--level 1` is strictest, `--level 8` the most lenient), Laravel-friendly issue handler defaults, and `runTaintAnalysis="true"`. Pass `--force` to overwrite an existing `psalm.xml` without prompting.
- `analyze` delegates to `vendor/bin/psalm` and passes the exit code through, so you can invoke `./vendor/bin/psalm` directly instead.

On the 3.x line (Psalm 6) security scanning is a separate mode rather than an extra check: enabling it makes Psalm report `Tainted...` issues and suppress every type issue. Keep `runTaintAnalysis` out of your `psalm.xml` there, which is why `init` on 3.x omits it, and pass the flag only for the security pass. Putting it in the config turns every run taint-only, including the `--set-baseline` run below.

```
./vendor/bin/psalm                  # types only
./vendor/bin/psalm --taint-analysis # security only
```

Psalm 7, and therefore the 4.x plugin line, merged the two: one run reports both.

Security scanning
-----------------

[](#security-scanning)

Plugin ships Laravel-specific taint stubs that track user input from source to sink across your entire codebase. Unlike pattern-matching tools, Psalm follows dataflow across function boundaries, so input that travels through helper functions, service classes, and any number of call layers is still caught.

VulnerabilityOWASPExample sinksSQL injectionA03:2021`orderBy()` column, `orderByRaw()`, `DB::select()`, `DB::statement()`, `DB::unprepared()`XSSA03:2021`response()`, `new HtmlString()`, mailable `html()`Shell injectionA03:2021`Process::path()->run()`, `app(Kernel::class)->call()`File traversalA01:2021`Storage::disk()->get()`, `->put()`, `->delete()`Open redirectA01:2021`redirect()`, `redirect()->to()`SSRFA10:2021`Http::withOptions()->get()` and the rest of `PendingRequest`Crypto misuseA02:2021encryption and hashing taint escape or unescapeTiming attack (CWE-208)A02:2021a secret compared with `===`, ``, or `strcmp()`You can read more about how the plugin's taint analysis works and what vulnerabilities it detects in [docs/security.md](docs/security.md).

Custom checks
-------------

[](#custom-checks)

13 Laravel-aware checks on top of Psalm's built-in diagnostics, each with a docs page explaining what it detects and how to fix it:

- [UndefinedModelRelation](docs/issues/UndefinedModelRelation.md): a relation name in `with()`, `load()`, or `whereHas()` that resolves to no relationship on the model.
- [UnknownModelAttribute](docs/issues/UnknownModelAttribute.md): a typo'd key passed to `create()`, `fill()`, or `update()` that matches no known attribute.
- [UnresolvableAppendedModelAttribute](docs/issues/UnresolvableAppendedModelAttribute.md): an `$appends` entry with no backing accessor, which is a runtime `BadMethodCallException` on `toArray()`.
- [OctaneIncompatibleBinding](docs/issues/OctaneIncompatibleBinding.md): a `singleton()` closure that resolves a request-scoped service, auto-enabled when `laravel/octane` is installed.
- [NoEnvOutsideConfig](docs/issues/NoEnvOutsideConfig.md): `env()` called outside the config directory, where it returns `null` once the config is cached.

See [docs/issues/index.md](docs/issues/index.md) for the full catalog.

Adopting it on an existing codebase
-----------------------------------

[](#adopting-it-on-an-existing-codebase)

The first run on an untouched project will report a lot. Fix the security findings first, then park the type issues in a [baseline](https://psalm.dev/docs/running_psalm/dealing_with_code_issues/#using-a-baseline-file) so only new code is checked. The noisier checks are opt-in and off by default, so nothing here depends on rewriting your codebase.

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

Important

`--set-baseline` records **every** issue it sees, security findings included, and a baselined `TaintedSql` stops being reported. After generating the baseline, delete the `` blocks from `psalm-baseline.xml`, otherwise the vulnerabilities you just found go quiet.

Full playbook, including the strictness ramp and how to turn down noise: [docs/adoption.md](docs/adoption.md).

Continuous integration
----------------------

[](#continuous-integration)

```
./vendor/bin/psalm-laravel add github
```

Writes a ready-to-commit `.github/workflows/psalm.yml` that runs the plugin on pull requests and on pushes to your default branch, and uploads security findings to GitHub Code Scanning. See [docs/github-actions.md](docs/github-actions.md) for what the generated workflow does and how to customize it.

Configuration
-------------

[](#configuration)

You can customize Psalm configuration using [XML config](https://psalm.dev/docs/running_psalm/configuration/)and/or [cli parameters](https://psalm.dev/docs/running_psalm/command_line_usage/).

For plugin configuration options, see [docs/config.md](docs/config.md).

Versions &amp; Dependencies
---------------------------

[](#versions--dependencies)

Maintained versions:

Laravel Psalm PluginPHPLaravelPsalmPlugin Status**4.x** (recommended)8.2+12, 137-betaStable3.x ([upgrade](UPGRADING.md#3x--4x))8.2+11, 12, 136Stable2.x ([upgrade](UPGRADING.md#2x--3x))8.0+8, 9, 10, 114, 5, 6Unmaintained1.x ([upgrade](UPGRADING.md#1x--2x))7.1+5, 6, 7, 83, 4UnmaintainedSee [releases](https://github.com/psalm/psalm-plugin-laravel/releases) for more details about supported PHP, Laravel and Psalm versions.

**How it works**Under the hood the plugin boots your actual Laravel application (or an [Orchestra Testbench](https://github.com/orchestral/testbench) skeleton when analyzing a package). This is not a just a classic static read of your code: config is loaded, facade aliases are resolved via `Illuminate\Foundation\AliasLoader` (including aliases from `config/app.php` and package discovery), and service providers run. It also ships hand-crafted stubs for taint analysis and special cases.

For Eloquent model metadata (casts, appended attributes, relations), the plugin goes a step further and instantiates each model class, constructor-less, via reflection, replaying its trait and attribute initializers to read the runtime-computed fields. This never needs a database connection: the model is never booted and no query runs. Column names and types instead come from parsing SQL schema dumps (`php artisan schema:dump`) and PHP migration files.

What that does and does not execute: booting the framework runs your service providers, exactly as any `php artisan` command does, so the plugin needs the same trust level you already give artisan. It never handles an HTTP request, never boots a model, never opens a database connection, and never runs a query.

Psalm-Laravel or Larastan?
--------------------------

[](#psalm-laravel-or-larastan)

**Use both.** They solve different problems:

- **Larastan** excels at Laravel-specific type rules: `model-property` validation, `view-string` checks, and 17+ custom rules.
- **Psalm-Laravel** in addition to type checks, it provides taint-based security analysis that PHPStan structurally [cannot offer](https://github.com/phpstan/phpstan/issues/8038), plus deep type support for Request data, Eloquent attributes, scopes, attributes, etc.

ToolPHP typesLaravel typesTaint analysisFree**Psalm-Laravel**YesYesYes, dataflowYesLarastanYesYesNoYesMagoYesNoSuperglobals onlyYesSonarQubePartialNoYes, genericPaid onlySemgrepNoNoYes, interfile paidFree tierSnyk CodeNoClaimedYes, genericFreemiumThe first three rows are from our own testing. The commercial rows summarize vendor documentation, so check their current tiers before relying on them.

Psalm and PHPStan use almost the same annotation syntax, so they work side by side without conflicts.

Contributing
------------

[](#contributing)

There are [contributing docs](docs/contributing/README.md) that may help you with contributions.

###  Health Score

79

—

ExcellentBetter than 100% of packages

Maintenance96

Actively maintained with recent releases

Popularity64

Solid adoption and visibility

Community53

Growing community involvement

Maturity93

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 71.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~15 days

Recently: every ~0 days

Total

176

Last Release

24d ago

Major Versions

v3.14.11 → v4.14.122026-07-12

v3.14.1592 → v4.15.02026-07-16

v3.15.0 → v4.15.12026-07-17

v3.15.1 → v4.15.22026-07-23

v3.15.2 → v4.15.32026-07-24

PHP version history (10 changes)1.2.0PHP ^7.1.3|^8

v1.3.0PHP ^7.2|^8

v1.4.1PHP ^7.3|^8

v1.5.2PHP ^7.3|^8.0

v2.0.0PHP ^8.0

v2.2.0PHP ^8.0.2

v2.10.0PHP ^8.1

v1.4.10PHP ^7.3 || ^8.0

v3.0.0-rc1PHP ^8.2

v4.0.0-beta.1PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/37a992956f2ceb043547091360fe71dacdd2b227d5450e7022b2a53660ba4e44?d=identicon)[muglug](/maintainers/muglug)

![](https://www.gravatar.com/avatar/819d5d9fe8f78d00cc5dd7972cbb9e4f049c9bff7186e0e401f3191b3f137885?d=identicon)[weirdan](/maintainers/weirdan)

---

Top Contributors

[![alies-dev](https://avatars.githubusercontent.com/u/5278175?v=4)](https://github.com/alies-dev "alies-dev (1880 commits)")[![mr-feek](https://avatars.githubusercontent.com/u/5747667?v=4)](https://github.com/mr-feek "mr-feek (246 commits)")[![lptn](https://avatars.githubusercontent.com/u/150333538?v=4)](https://github.com/lptn "lptn (101 commits)")[![muglug](https://avatars.githubusercontent.com/u/2292638?v=4)](https://github.com/muglug "muglug (85 commits)")[![Nielsvanpach](https://avatars.githubusercontent.com/u/10651054?v=4)](https://github.com/Nielsvanpach "Nielsvanpach (84 commits)")[![actions-user](https://avatars.githubusercontent.com/u/65916846?v=4)](https://github.com/actions-user "actions-user (65 commits)")[![caugner](https://avatars.githubusercontent.com/u/495429?v=4)](https://github.com/caugner "caugner (41 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (26 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (17 commits)")[![mzur](https://avatars.githubusercontent.com/u/2457311?v=4)](https://github.com/mzur "mzur (10 commits)")[![ronb-lendesk](https://avatars.githubusercontent.com/u/55106709?v=4)](https://github.com/ronb-lendesk "ronb-lendesk (9 commits)")[![danog](https://avatars.githubusercontent.com/u/7339644?v=4)](https://github.com/danog "danog (6 commits)")[![tm1000](https://avatars.githubusercontent.com/u/564256?v=4)](https://github.com/tm1000 "tm1000 (5 commits)")[![asbiin](https://avatars.githubusercontent.com/u/25419741?v=4)](https://github.com/asbiin "asbiin (4 commits)")[![MDG11](https://avatars.githubusercontent.com/u/59790837?v=4)](https://github.com/MDG11 "MDG11 (4 commits)")[![tjmmm](https://avatars.githubusercontent.com/u/2571506?v=4)](https://github.com/tjmmm "tjmmm (3 commits)")[![crynobone](https://avatars.githubusercontent.com/u/172966?v=4)](https://github.com/crynobone "crynobone (3 commits)")[![pthiers](https://avatars.githubusercontent.com/u/1180952?v=4)](https://github.com/pthiers "pthiers (3 commits)")[![yaegassy](https://avatars.githubusercontent.com/u/188642?v=4)](https://github.com/yaegassy "yaegassy (2 commits)")[![dpash](https://avatars.githubusercontent.com/u/118778?v=4)](https://github.com/dpash "dpash (2 commits)")

---

Tags

laravelphpphp-static-analysispsalmpsalm-pluginsecuritysecurity-auditstatic-analysislaraveldevpsalmpsalm-plugin

###  Code Quality

TestsPHPUnit

Static AnalysisRector

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/psalm-plugin-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/psalm-plugin-laravel/health.svg)](https://phpackages.com/packages/psalm-plugin-laravel)
```

###  Alternatives

[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

265.2k](/packages/aedart-athenaeum)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k16.3M154](/packages/laravel-pulse)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k31.8M162](/packages/laravel-cashier)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45844.8k1](/packages/pressbooks-pressbooks)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9922.4M146](/packages/roots-acorn)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
