baspa / larascan
A security-focused static analysis package for Laravel applications
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/console: ^11.0||^12.0||^13.0
- illuminate/contracts: ^11.0||^12.0||^13.0
- illuminate/support: ^11.0||^12.0||^13.0
- laravel/agent-detector: ^2.0
- nikic/php-parser: ^5.0
- spatie/laravel-package-tools: ^1.16
- symfony/process: ^6.4||^7.0||^8.0
- symfony/yaml: ^6.4||^7.0||^8.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0||^10.0||^11.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
This package is auto-updated.
Last update: 2026-06-02 09:26:14 UTC
README
LaraScan
Security-focused static analysis for Laravel applications. One artisan command, 81 checks across config, cookies, headers, auth, routing, models, SQL, XSS, files, injection, crypto, dependencies and more.
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
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
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
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)
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.
Output formats
| Flag | Default for | Description |
|---|---|---|
| (none) | TTY / humans | Categorized output with a Report Card at the end |
--format=json |
AI agents | Structured JSON. Auto-selected when laravel/agent-detector flags the run as an agent (Claude Code, Cursor, Codex, Copilot, etc.). |
Force JSON manually with LARASCAN_AGENT_MODE=1 or --format=json.
Configuration
Published config/larascan.php controls:
fail_on— severity threshold for non-zero exit code (critical|high|medium|low|info, defaulthigh)checks— per-check enable map ('cookies.session-secure' => ['enabled' => false])ignore— glob patterns to skip during AST scanstools— override binary paths via env vars:LARASCAN_COMPOSER_BIN,LARASCAN_NPM_BIN,LARASCAN_SEMGREP_BIN
See docs/configuration.md for full details.
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.
What's checked?
81 checks across 16 categories. Some require optional packages — those checks self-skip when the package isn't installed.
Show all 81 checks
Config (config.*) — 9
config.app-debug— APP_DEBUG must be false in productionconfig.app-key— APP_KEY must be setconfig.app-env— APP_ENV must not be a development value in productionconfig.env-not-committed— .env must be gitignored and never committedconfig.env-example-sync— .env and .env.example must share key setsconfig.env-calls-outside-config— env() calls outside config/ defeat config cachingconfig.log-level— Default log channel must not be at debug in productionconfig.debug-blacklist— debug_blacklist must redact sensitive env keys when debug is onconfig.trusted-proxies— Trusted proxies must not be wildcard
Cookies & sessions (cookies.*) — 7
cookies.session-secure— SESSION_SECURE_COOKIE must be true in productioncookies.session-http-only— SESSION_HTTP_ONLY must be truecookies.session-same-site— SESSION_SAME_SITE must be lax or strictcookies.session-encrypt— session.encrypt should be truecookies.session-lifetime— session.lifetime must be within a reasonable rangecookies.encrypt-middleware— EncryptCookies middleware must be registeredcookies.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 enabledheaders.hsts— HSTS header middleware must be active in productionheaders.x-content-type-options— X-Content-Type-Options: nosniff middleware must be activeheaders.x-frame-options— X-Frame-Options or frame-ancestors must be setheaders.referrer-policy— Referrer-Policy header middleware should be activeheaders.csp-defined— CSP middleware must be active (requires 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 abase-uridirective
Auth (auth.*) — 10
auth.bcrypt-rounds— BCRYPT_ROUNDS must be 12 or higherauth.sanctum-expiration— Sanctum tokens must have an expiration (requires laravel/sanctum)auth.login-throttle— Login routes must have throttle middlewareauth.password-column-plain— User model must hide or hash the password columnauth.signed-routes-verify— Email verification routes must use signed middlewareauth.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 parametersauth.otp-rate-limiting— OTP/2FA verification routes must havethrottle:middlewareauth.registration-rate-limit— Registration routes must havethrottle:middlewareauth.jwt-missing-expiration— Tymon JWTjwt.ttlmust not be null or 0
CSRF (csrf.*) — 2
csrf.middleware-disabled— VerifyCsrfToken middleware must be registeredcsrf.except-suspicious— CSRF except list must not contain wildcard patterns
Routing (routing.*) — 2
routing.state-mutating-get— GET routes must not invokedestroy/delete/remove/deactivate/disablecontroller methodsrouting.api-http-only— API routes underapi/*must enforce HTTPS whenAPP_URLishttp://
Models (models.*) — 4
models.unguarded— Eloquent models must not use$guarded = []models.unguard-call— No staticModel::unguard()calls in application codemodels.foreign-key-fillable— Foreign key columns should not be in$fillablemodels.force-fill-user-input—forceFill()calls bypass mass-assignment protection
SQL (sql.*) — 5
sql.raw-user-input— DB::raw / whereRaw / selectRaw with user inputsql.raw-order-by— orderByRaw with user inputsql.variable-table-column— Variable arguments to DB::table / from / selectsql.validation-rule-injection— Validation rules from variable sourcesql.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 XSSxss.html-string—Illuminate\Support\HtmlStringproduces unescaped HTMLxss.url-javascript-protocol—javascript:URLs in href/src are XSS sinksxss.htmlstring-cast— Eloquent$casts/casts()must not cast attributes toHtmlString::class
Files (files.*) — 4
files.path-traversal— Storage/File operations with user-controlled pathsfiles.unlink-user-input—unlink()/rmdir()in application codefiles.upload-mimes-validation— Validation by extension rather than MIMEfiles.public-executable-uploads— Upload rules allowing .php/.phtml/.phar
Injection (injection.*) — 5
injection.command—exec/shell_exec/system/passthrucallsinjection.process-shell—Process::fromShellCommandline()usageinjection.unserialize—unserialize()of any inputinjection.open-redirect—redirect()with user-controlled URLinjection.host-header—app.urlmissing or pointing to localhost
Crypto & secrets (crypto.*) — 5
crypto.weak-hash— md5/sha1 for security purposescrypto.weak-random— rand/mt_rand/uniqid for security tokenscrypto.cipher-not-pinned—config/app.phpdoes not pin the ciphercrypto.hardcoded-secret— High-entropy secrets or known token patterns in codecrypto.password-self-generated— Weak generators (Str::random,md5,uniqid,random_bytes,bin2hex) must not be used in password contexts — useStr::password()
Dependencies (dependencies.*) — 4
dependencies.composer-audit— wrapscomposer auditfor PHP CVE detectiondependencies.npm-audit— wrapsnpm auditwhen apackage.jsonis presentdependencies.minimum-stability-dev— composer.json minimum-stability is 'dev' without prefer-stabledependencies.outdated-php— PHP version at or near end-of-life
PHP (php.*) — 5
php.expose-php— expose_php must be offphp.display-errors— display_errors must be off in productionphp.allow-url-fopen— allow_url_fopen should be offphp.public-sensitive-files— No .env / .git / .sql backups in public/php.phpinfo— Nophpinfo()calls in application code
Logging (logging.*) — 3
logging.dd-dump-debug— Nodd()/dump()/var_dump()in application codelogging.custom-error-pages—resources/views/errors/500.blade.phpand503.blade.phpmust existlogging.sensitive-in-log-context— Log context arrays must not contain password/token/secret keys
Repo & CI (repo.*) — 4
repo.dependabot—.github/dependabot.ymlshould exist for automated dep updatesrepo.gitleaks-history— No high-entropy secrets in git history (last 100 commits)repo.debug-toolbars— Debug packages (debugbar, telescope) must be inrequire-devonlyrepo.security-txt—public/.well-known/security.txtshould exist so researchers know how to report issues
Requirements
- PHP 8.3+
- Laravel 11 / 12 / 13
Contributing
See CONTRIBUTING.md. Tests must pass, PHPStan must be clean at level 8, Pint must be clean.
Security
If you discover a security issue, please email hello@baspa.dev instead of opening a public issue.
Inspired by
- Enlightn — the original Laravel performance + security scanner. Its analyzer-per-check pattern and report card concept shaped how LaraScan is structured.
- Securing Laravel — Stephen Rees-Carter's writing and newsletter, the practical reference for what to check and why it matters.
License
The MIT License (MIT). See LICENSE.md.
