baspa/larascan
最新稳定版本:v3.0.0
Composer 安装命令:
composer require baspa/larascan
包简介
A security-focused static analysis package for Laravel applications
关键字:
README 文档
README
LaraScan
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
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.). |
--format=sarif |
GitHub Code Scanning | SARIF 2.1.0 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
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.
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 severity | SARIF level | security-severity |
|---|---|---|
| critical | error | 9.8 |
| high | error | 8.0 |
| medium | warning | 5.5 |
| low | note | 3.0 |
| info | note | 0.0 |
Findings 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)
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
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.
| Flag | Description |
|---|---|
--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?
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 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 wildcardconfig.mail-smtp-encryption— Remote SMTP mailers must force TLS encryption
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.*) — 5
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/.pharfiles.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/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
Ecosystem packages (ecosystem.*) — 5
ecosystem.telescope-production— Telescope must not be enabled in production without an explicitviewTelescopegate (requires laravel/telescope)ecosystem.horizon-gate— HorizonviewHorizongate must not be trivially true, and must be defined in production (requires laravel/horizon)ecosystem.pulse-gate— PulseviewPulsegate must not be trivially true, and must be defined in production (requires laravel/pulse)ecosystem.debugbar-enabled— Debugbar must not be enabled at runtime in production (requires barryvdh/laravel-debugbar)ecosystem.livewire-upload-rules— Customized Livewire temporary uploads must keep amax:size rule and not strip throttle middleware (requires livewire/livewire)
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.
统计信息
- 总下载量: 54
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-02
