PHPackages                             baspa/larascan - 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. baspa/larascan

ActiveLibrary[Security](/categories/security)

baspa/larascan
==============

A security-focused static analysis package for Laravel applications

v3.0.2(1mo ago)3340MITPHPPHP ^8.3CI passing

Since May 15Pushed 1mo agoCompare

[ Source](https://github.com/Baspa/larascan)[ Packagist](https://packagist.org/packages/baspa/larascan)[ Docs](https://github.com/baspa/larascan)[ GitHub Sponsors](https://github.com/Baspa)[ RSS](/packages/baspa-larascan/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (36)Versions (15)Used By (0)

 [![LaraScan — Scan Laravel applications for vulnerabilities, insecure configs and risky code](art/larascan-logo.png)](art/larascan-logo.png)

LaraScan
========

[](#larascan)

[![Latest Version](https://camo.githubusercontent.com/80fef6d3783c21e944bbec2a1fa10e6e7055caa6c599ec174a9cbdad9c9a5f82/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f62617370612f6c6172617363616e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/baspa/larascan)[![Tests](https://camo.githubusercontent.com/8190375a91db6a29f945fe48da02725b977702c470831deece523bd58d276aa6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f62617370612f6c6172617363616e2f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/baspa/larascan/actions/workflows/tests.yml)[![PHPStan](https://camo.githubusercontent.com/d98b27e997b6bb62153c617379f7d602f67147a88ac8b85e6ed26a11440b7a93/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f62617370612f6c6172617363616e2f7068707374616e2e796d6c3f6272616e63683d6d61696e266c6162656c3d7068707374616e2532306c6576656c25323038267374796c653d666c61742d737175617265)](https://github.com/baspa/larascan/actions/workflows/phpstan.yml)[![Coverage](https://camo.githubusercontent.com/ac28973bb6a12cd29c257ae8b63ac51d4651b532502badb97a0cd5b9fcc4dd46/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f62617370612f6c6172617363616e3f7374796c653d666c61742d737175617265)](https://codecov.io/gh/baspa/larascan)[![Downloads](https://camo.githubusercontent.com/71c8d17be0ef563c9537c31e59933107c773a7f5561b526cb4f39ef7d9507272/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f62617370612f6c6172617363616e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/baspa/larascan)[![License](https://camo.githubusercontent.com/707f2f1bfdf64f5a86dccb2eece6a14e6df3cce82f40ab90eb357bcaa1b86d4d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f62617370612f6c6172617363616e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)

Security-focused static analysis for Laravel applications. One artisan command, **88 checks** across config, cookies, headers, auth, routing, models, SQL, XSS, files, injection, crypto, dependencies, ecosystem packages and more — plus an optional runtime probe that verifies headers on the live app.

> **Why LaraScan?** Most Laravel security issues come from misconfiguration or forgotten dev settings in production — debug on, secure cookies off, hardcoded API keys in code. LaraScan scans for them in one shot, AST-based where it matters, with sane defaults and a clean CI workflow.

Example
-------

[](#example)

```
larascan security scan
════════════════════════════════════════════

  Application configuration
  ─────────────────────────
     ✗ config.app-env
        └─ INFO     APP_ENV is 'local' — leaks development-mode behavior in production.
     ✗ config.env-example-sync
        ├─ LOW      Keys present in .env but missing from .env.example: MISTRAL_API_KEY
        └─ LOW      Keys present in .env.example but missing from .env: RESPONSE_CACHE_*

  Cookies & sessions
  ──────────────────
     ✗ cookies.session-encrypt
        └─ HIGH     session.encrypt is false — session payloads are stored in plaintext.

════════════════════════════════════════════
  Report Card
════════════════════════════════════════════

  Application configuration ███████████░░░░░░░░░  57%   (4/7)
  Cookies & sessions       ██████████████░░░░░░  71%   (5/7)
  HTTP headers             ████░░░░░░░░░░░░░░░░  20%   (1/5)
  ...

  Total: 45 passed   19 failed   6 skipped   0 errored
  Highest severity: CRITICAL

```

Install
-------

[](#install)

```
composer require baspa/larascan --dev
php artisan larascan:install
```

The install command publishes `config/larascan.php` and optionally `.github/workflows/larascan.yml` (CI workflow stub).

Usage
-----

[](#usage)

```
php artisan larascan                  # run all enabled checks
php artisan larascan --only-failed    # hide passed + skipped
php artisan larascan --category=config
php artisan larascan --fail-on=high   # CI threshold (exit 1 on findings ≥ high)
php artisan larascan:list             # list all registered checks
```

### Advise (heuristic, non-gating)

[](#advise-heuristic-non-gating)

```
php artisan larascan:advise                  # surface heuristic security advisories
php artisan larascan:advise --advice=advise.auth.*
php artisan larascan:advise --category=auth
```

Advise is intentionally non-gating: exit code is always 0. For architectural items that no scanner can detect, see [`docs/manual-security-checklist.md`](docs/manual-security-checklist.md).

### Output formats

[](#output-formats)

FlagDefault forDescription(none)TTY / humansCategorized output with a Report Card at the end`--format=json`AI agentsStructured JSON. Auto-selected when [`laravel/agent-detector`](https://github.com/laravel/agent-detector) flags the run as an agent (Claude Code, Cursor, Codex, Copilot, etc.).`--format=sarif`GitHub Code Scanning[SARIF 2.1.0](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning) report with one result per finding.Force JSON manually with `LARASCAN_AGENT_MODE=1` or `--format=json`.

Any format can be written to a file with `--output=PATH`. For `--format=json` and `--format=sarif`, stdout still gets the human report (so CI logs stay readable); with `--format=human`, stdout only gets a `Report written to ...` confirmation. The exit code is unchanged either way.

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

[](#configuration)

Published `config/larascan.php` controls:

- `fail_on` — severity threshold for non-zero exit code (`critical|high|medium|low|info`, default `high`)
- `checks` — per-check enable map (`'cookies.session-secure' => ['enabled' => false]`)
- `ignore` — glob patterns to skip during AST scans
- `tools` — override binary paths via env vars: `LARASCAN_COMPOSER_BIN`, `LARASCAN_NPM_BIN`, `LARASCAN_SEMGREP_BIN`

See [docs/configuration.md](docs/configuration.md) for full details.

CI integration
--------------

[](#ci-integration)

The published workflow runs on PR + push to main + nightly. It uses `--only-failed` to keep CI logs lean, with the Report Card at the end for the overview.

```
php artisan larascan:install --workflow
```

Exit codes: `0` clean, `1` findings ≥ `--fail-on`, `2` a check errored. See [docs/ci-integration.md](docs/ci-integration.md).

### SARIF / GitHub Code Scanning

[](#sarif--github-code-scanning)

Findings can show up as Code Scanning alerts on the Security tab and as PR annotations:

```
php artisan larascan --format=sarif --output=larascan.sarif
```

The published workflow already does this and uploads the report via `github/codeql-action/upload-sarif` (the workflow grants `security-events: write`; private repos need GitHub Advanced Security — remove the upload step if unavailable).

Severity mapping:

Larascan severitySARIF level`security-severity`criticalerror9.8higherror8.0mediumwarning5.5lownote3.0infonote0.0Findings without a file (config-level checks like `config.app-debug`) are anchored to `composer.json:1` so GitHub doesn't drop them; those results carry a `larascan.synthesizedLocation` property.

Adopting LaraScan on an existing app (baseline)
-----------------------------------------------

[](#adopting-larascan-on-an-existing-app-baseline)

A mature codebase will light up on the first scan. Rather than fixing everything before CI can go green, record the current findings as a **baseline** so CI only fails on *new* findings:

```
php artisan larascan:baseline   # writes larascan-baseline.json
git add larascan-baseline.json && git commit -m "Add larascan baseline"
```

From then on, plain `php artisan larascan` runs suppress baselined findings — they're counted (`N baselined`) rather than hidden, so you can still see them — and only findings that aren't in the baseline count toward the `--fail-on` threshold. Chip away at the baselined findings over time; re-run `larascan:baseline` to shrink the file.

Baseline identity is line-insensitive: a finding is matched on a hash of its check id, file and normalized message, so unrelated edits that shift line numbers don't break the baseline. When the source has changed enough that baselined findings no longer occur, the scan reports `N stale baseline entries` with a hint to re-run the command and prune them.

```
php artisan larascan --baseline=path/to/baseline.json   # override the path
php artisan larascan --no-baseline                       # ignore the baseline entirely
```

Path resolution order: `--baseline` flag, then `config('larascan.baseline')`, then an implicit `larascan-baseline.json` in the project root if present. An explicitly named baseline (flag or config) that's missing or invalid is an error; the implicit default may simply be absent.

Runtime probe
-------------

[](#runtime-probe)

Static checks confirm the *config* is right; they can't tell you whether a middleware actually runs or whether a proxy strips a header on the way out. `larascan:probe` sends **one real HTTP GET** to the running app and verifies the security headers and cookie flags are actually present in the response:

```
php artisan larascan:probe --url=https://staging.example.test
```

The target URL resolves from `--url`, then `config('larascan.probe.url')` (env `LARASCAN_PROBE_URL`), then `app.url`. The probe checks HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, CSP, cookie `Secure`/`HttpOnly`/`SameSite` flags, `Server`/`X-Powered-By` disclosure, and the http→https redirect. These are reported under `probe.*` check ids, distinct from the static `headers.*` checks.

Findings against local targets (`localhost`, `127.0.0.1`, `*.test`, `*.local`) are downgraded to Info — probing a dev box shouldn't fail CI.

FlagDescription`--url=URL`Target URL (overrides config/`app.url`)`--fail-on=SEVERITY`Severity threshold for non-zero exit (default from `larascan.fail_on`, else `high`)`--probe=PATTERN`Filter probes by id pattern, repeatable (e.g. `--probe=probe.cookie*`)`--timeout=SECONDS`Request timeout (default 5)`--insecure`Skip TLS certificate verification`--ignore-errors`Exit 0 even when the request fails`--only-failed`Hide passed and skipped probes`--format=human|json`Output format (json auto-selected for agents)What's checked?
---------------

[](#whats-checked)

88 checks across 17 categories. Some require optional packages — those checks self-skip when the package isn't installed.

**Show all 88 checks****Config (`config.*`)** — 10

- `config.app-debug` — APP\_DEBUG must be false in production
- `config.app-key` — APP\_KEY must be set
- `config.app-env` — APP\_ENV must not be a development value in production
- `config.env-not-committed` — .env must be gitignored and never committed
- `config.env-example-sync` — .env and .env.example must share key sets
- `config.env-calls-outside-config` — env() calls outside config/ defeat config caching
- `config.log-level` — Default log channel must not be at debug in production
- `config.debug-blacklist` — debug\_blacklist must redact sensitive env keys when debug is on
- `config.trusted-proxies` — Trusted proxies must not be wildcard
- `config.mail-smtp-encryption` — Remote SMTP mailers must force TLS encryption

**Cookies &amp; sessions (`cookies.*`)** — 7

- `cookies.session-secure` — SESSION\_SECURE\_COOKIE must be true in production
- `cookies.session-http-only` — SESSION\_HTTP\_ONLY must be true
- `cookies.session-same-site` — SESSION\_SAME\_SITE must be lax or strict
- `cookies.session-encrypt` — session.encrypt should be true
- `cookies.session-lifetime` — session.lifetime must be within a reasonable range
- `cookies.encrypt-middleware` — EncryptCookies middleware must be registered
- `cookies.encrypt-excludes` — Sensitive cookies must not be in EncryptCookies::$except

**Headers (`headers.*`)** — 8

- `headers.cors-wildcard` — CORS allowed\_origins must not be wildcard with credentials enabled
- `headers.hsts` — HSTS header middleware must be active in production
- `headers.x-content-type-options` — X-Content-Type-Options: nosniff middleware must be active
- `headers.x-frame-options` — X-Frame-Options or frame-ancestors must be set
- `headers.referrer-policy` — Referrer-Policy header middleware should be active
- `headers.csp-defined` — CSP middleware must be active *(requires [spatie/laravel-csp](https://github.com/spatie/laravel-csp))*
- `headers.csp-unsafe-inline` — CSP must not use unsafe-inline or unsafe-eval *(requires spatie/laravel-csp)*
- `headers.csp-base-uri` — Spatie CSP policy must include a `base-uri` directive

**Auth (`auth.*`)** — 10

- `auth.bcrypt-rounds` — BCRYPT\_ROUNDS must be 12 or higher
- `auth.sanctum-expiration` — Sanctum tokens must have an expiration *(requires [laravel/sanctum](https://github.com/laravel/sanctum))*
- `auth.login-throttle` — Login routes must have throttle middleware
- `auth.password-column-plain` — User model must hide or hash the password column
- `auth.signed-routes-verify` — Email verification routes must use signed middleware
- `auth.api-ability-scoping` — Sanctum tokens must be created with explicit abilities *(requires laravel/sanctum)*
- `auth.signed-url-no-params` — Signed URLs must include user-bound route parameters
- `auth.otp-rate-limiting` — OTP/2FA verification routes must have `throttle:` middleware
- `auth.registration-rate-limit` — Registration routes must have `throttle:` middleware
- `auth.jwt-missing-expiration` — Tymon JWT `jwt.ttl` must not be null or 0

**CSRF (`csrf.*`)** — 2

- `csrf.middleware-disabled` — VerifyCsrfToken middleware must be registered
- `csrf.except-suspicious` — CSRF except list must not contain wildcard patterns

**Routing (`routing.*`)** — 2

- `routing.state-mutating-get` — GET routes must not invoke `destroy`/`delete`/`remove`/`deactivate`/`disable` controller methods
- `routing.api-http-only` — API routes under `api/*` must enforce HTTPS when `APP_URL` is `http://`

**Models (`models.*`)** — 4

- `models.unguarded` — Eloquent models must not use `$guarded = []`
- `models.unguard-call` — No static `Model::unguard()` calls in application code
- `models.foreign-key-fillable` — Foreign key columns should not be in `$fillable`
- `models.force-fill-user-input` — `forceFill()` calls bypass mass-assignment protection

**SQL (`sql.*`)** — 5

- `sql.raw-user-input` — DB::raw / whereRaw / selectRaw with user input
- `sql.raw-order-by` — orderByRaw with user input
- `sql.variable-table-column` — Variable arguments to DB::table / from / select
- `sql.validation-rule-injection` — Validation rules from variable source
- `sql.orwhere-scope-bypass` — `->orWhere(...)` must not be chained directly off `->where(...)` outside a closure group

**XSS (`xss.*`)** — 4

- `xss.blade-unescaped` — Blade `{!! $var !!}` with PHP variables risks XSS
- `xss.html-string` — `Illuminate\Support\HtmlString` produces unescaped HTML
- `xss.url-javascript-protocol` — `javascript:` URLs in href/src are XSS sinks
- `xss.htmlstring-cast` — Eloquent `$casts` / `casts()` must not cast attributes to `HtmlString::class`

**Files (`files.*`)** — 5

- `files.path-traversal` — Storage/File operations with user-controlled paths
- `files.unlink-user-input` — `unlink()`/`rmdir()` in application code
- `files.upload-mimes-validation` — Validation by extension rather than MIME
- `files.public-executable-uploads` — Upload rules allowing .php/.phtml/.phar
- `files.disk-visibility` — Public-visibility disk with a sensitive name/root, or an s3 disk with no explicit visibility

**Injection (`injection.*`)** — 5

- `injection.command` — `exec`/`shell_exec`/`system`/`passthru` calls
- `injection.process-shell` — `Process::fromShellCommandline()` usage
- `injection.unserialize` — `unserialize()` of any input
- `injection.open-redirect` — `redirect()` with user-controlled URL
- `injection.host-header` — `app.url` missing or pointing to localhost

**Crypto &amp; secrets (`crypto.*`)** — 5

- `crypto.weak-hash` — md5/sha1 for security purposes
- `crypto.weak-random` — rand/mt\_rand/uniqid for security tokens
- `crypto.cipher-not-pinned` — `config/app.php` does not pin the cipher
- `crypto.hardcoded-secret` — High-entropy secrets or known token patterns in code
- `crypto.password-self-generated` — Weak generators (`Str::random`, `md5`, `uniqid`, `random_bytes`, `bin2hex`) must not be used in password contexts — use `Str::password()`

**Dependencies (`dependencies.*`)** — 4

- `dependencies.composer-audit` — wraps `composer audit` for PHP CVE detection
- `dependencies.npm-audit` — wraps `npm audit` when a `package.json` is present
- `dependencies.minimum-stability-dev` — composer.json minimum-stability is 'dev' without prefer-stable
- `dependencies.outdated-php` — PHP version at or near end-of-life

**PHP (`php.*`)** — 5

- `php.expose-php` — expose\_php must be off
- `php.display-errors` — display\_errors must be off in production
- `php.allow-url-fopen` — allow\_url\_fopen should be off
- `php.public-sensitive-files` — No .env / .git / .sql backups in public/
- `php.phpinfo` — No `phpinfo()` calls in application code

**Logging (`logging.*`)** — 3

- `logging.dd-dump-debug` — No `dd()` / `dump()` / `var_dump()` in application code
- `logging.custom-error-pages` — `resources/views/errors/500.blade.php` and `503.blade.php` must exist
- `logging.sensitive-in-log-context` — Log context arrays must not contain password/token/secret keys

**Repo &amp; CI (`repo.*`)** — 4

- `repo.dependabot` — `.github/dependabot.yml` should exist for automated dep updates
- `repo.gitleaks-history` — No high-entropy secrets in git history (last 100 commits)
- `repo.debug-toolbars` — Debug packages (debugbar, telescope) must be in `require-dev` only
- `repo.security-txt` — `public/.well-known/security.txt` should exist so researchers know how to report issues

**Ecosystem packages (`ecosystem.*`)** — 5

- `ecosystem.telescope-production` — Telescope must not be enabled in production without an explicit `viewTelescope` gate *(requires [laravel/telescope](https://github.com/laravel/telescope))*
- `ecosystem.horizon-gate` — Horizon `viewHorizon` gate must not be trivially true, and must be defined in production *(requires [laravel/horizon](https://github.com/laravel/horizon))*
- `ecosystem.pulse-gate` — Pulse `viewPulse` gate must not be trivially true, and must be defined in production *(requires [laravel/pulse](https://github.com/laravel/pulse))*
- `ecosystem.debugbar-enabled` — Debugbar must not be enabled at runtime in production *(requires [barryvdh/laravel-debugbar](https://github.com/barryvdh/laravel-debugbar))*
- `ecosystem.livewire-upload-rules` — Customized Livewire temporary uploads must keep a `max:` size rule and not strip throttle middleware *(requires [livewire/livewire](https://github.com/livewire/livewire))*

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 11 / 12 / 13

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

[](#contributing)

See [CONTRIBUTING.md](CONTRIBUTING.md). Tests must pass, PHPStan must be clean at level 8, Pint must be clean.

Security
--------

[](#security)

If you discover a security issue, please email  instead of opening a public issue.

Inspired by
-----------

[](#inspired-by)

- [Enlightn](https://github.com/enlightn/enlightn) — the original Laravel performance + security scanner. Its analyzer-per-check pattern and report card concept shaped how LaraScan is structured.
- [Securing Laravel](https://securinglaravel.com/) — Stephen Rees-Carter's writing and newsletter, the practical reference for what to check and why it matters.

License
-------

[](#license)

The MIT License (MIT). See [LICENSE.md](LICENSE.md).

###  Health Score

48

—

FairBetter than 94% of packages

Maintenance94

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 96.7% 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 ~4 days

Total

10

Last Release

30d ago

Major Versions

v1.1.1 → 2.1.x-dev2026-05-16

v2.1.0 → v3.0.02026-06-11

PHP version history (2 changes)v1.0.0PHP ^8.2

v2.0.1PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/10845460?v=4)[Bas van Dinther](/maintainers/Baspa)[@Baspa](https://github.com/Baspa)

---

Top Contributors

[![Baspa](https://avatars.githubusercontent.com/u/10845460?v=4)](https://github.com/Baspa "Baspa (116 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")

---

Tags

laravelstatic analysissecurityAuditcspxssowaspSQL InjectionscannerSASTdependency-scanning

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/baspa-larascan/health.svg)

```
[![Health](https://phpackages.com/badges/baspa-larascan/health.svg)](https://phpackages.com/packages/baspa-larascan)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[spatie/laravel-health

Monitor the health of a Laravel application

87912.0M177](/packages/spatie-laravel-health)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77922.3M186](/packages/laravel-mcp)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.6k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

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