elohim/laravel-security-check
Laravel security checker that scans your application for common vulnerabilities, misconfigurations, and risky dependencies, then reports actionable fixes so you can harden your app before deployment.
This package is a configuration linter for Laravel: it inspects your config/*.php and .env values against a set of known-risky defaults (debug mode, weak session settings, insecure cookies, exposed storage, etc.) and reports violations. It is not a runtime firewall or a dependency scanner — think of it as a pre-deploy sanity check that catches the "we left APP_DEBUG=true in production" class of mistakes.
Minimal setup:
composer require --dev elohim/laravel-security-check
php artisan vendor:publish --tag=security-check-config # if a config file is offered
php artisan list | grep -i security # confirm the command name
First use case: run the check against your production environment context, not local:
php artisan security:check --env=production
Where to look first:
php artisan list — confirm the actual command signature and available flags (--env, --json, --fail-on-warning).config/security-check.php or similar) — this is where rule severity and exclusions live.README.md — rule names differ between releases; a composer show elohim/laravel-security-check after install tells you what version you're pinned to.The package is --dev-appropriate because it validates configuration, not runtime behavior. Running it in production composer install --no-dev will remove it, so either keep it in require or run it from a CI stage that installs dev dependencies.
Pattern 1 — Pre-deploy gate in CI. The highest-value use. Add a step that runs the check with production-like env vars injected, and fail the build on any critical findings:
# .github/workflows/deploy.yml
- name: Security config check
run: |
cp .env.example .env
php artisan key:generate
php artisan security:check --env=production --fail-on=critical
Set APP_ENV=production and representative values (mail, session, cache, queue) before the run — the check evaluates whatever config() resolves to, so an empty .env produces noise about missing credentials.
Pattern 2 — JSON output for dashboards. Pipe --json into a jq filter or a PR commenter so reviewers see exactly which config keys are flagged and why:
php artisan security:check --json | jq '.[] | select(.severity=="critical") | {rule, message, fix}'
This is useful when you're onboarding a legacy app — you get a triage list rather than one giant red block.
Pattern 3 — Post-deploy smoke test. Run the command against the live container as part of your health check:
ssh deploy@app "cd /var/www && php artisan security:check --env=production --fail-on=critical"
This catches drift: someone edited .env on the box, re-enabled debug for a hotfix, and forgot to revert. Combine with your deploy script so a failing check aborts the release before traffic shifts.
Pattern 4 — Baseline for new projects. Run once on a fresh laravel new to see what the linter considers risky, then decide per rule. Treat the first run as documentation of secure-by-default choices; don't silently suppress everything to get green.
Integration tip: if you use Laravel Sail, run the check inside the container so APP_ENV/DB credentials match the runtime. sail artisan security:check works because the artisan binary is proxied.
Env resolution differs from production. The check sees the config() values loaded in the current process. If your CI injects production secrets via a vault step after the check, the check runs against staging values and lies to you. Run it after env injection, or supply a .env.production copy explicitly.
False positives are the main maintenance cost. Rules that flag APP_DEBUG=false are fine; rules that flag database session driver or file cache driver as "insecure" will annoy teams using single-node setups. Use the config file's per-rule disable list rather than editing vendor files. If the package lacks a disable mechanism, wrap the command in a CI step that greps out known-acceptable findings — brittle, but a stopgap.
--env flag vs. actual environment. --env=production changes which .env file Laravel loads only if your framework version supports it in that command context. Most such artisan commands run in the default environment unless you also set APP_ENV. Verify with php artisan security:check --env=production -v that the resolved environment matches expectation — a mismatch here is the single most common cause of "the check passes but production is broken."
Severity is not a substitute for judgment. A "medium" finding like missing Strict-Transport-Security may be irrelevant if TLS terminates upstream. Conversely, a "low" finding around .env file permissions could be the most exploitable thing in your stack. Read the rule text, don't just chase the color.
Debugging output. If the command silently exits 0 on a config you know is unsafe, the rule likely can't resolve the value — e.g., it looks for config('session.secure') but you set SESSION_SECURE_COOKIE with a typo. Run php artisan tinker and inspect config('session') directly to confirm the key exists before blaming the package.
Extension points. If the package exposes a rule interface (check src/Rules or the README), register custom checks for your org's standards — e.g., "no dd() in app/", "all mailers must use TLS". This is where the package earns its keep; the bundled rules only cover Laravel defaults, and your house rules are usually the ones that matter.
Pin the version. With 60 stars and a single maintainer, releases are infrequent. Constrain with "elohim/laravel-security-check": "^1.0" and review the changelog before bumping — rule set changes can flip a passing CI green to red overnight, which is exactly what you want from a security tool, but not at 5pm on a Friday.
Complement, don't replace. Pair this with composer audit, enlightn, or a static analyzer. Configuration is one slice of the attack surface; dependency CVEs and app-level logic are separate checks that this package does not perform.
How can I help you explore Laravel packages today?