bigdevwhale / laravel-secure-baseline
A Laravel package for security scanning and baseline enforcement with auto-fix capabilities
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/bigdevwhale/laravel-secure-baseline
Requires
- php: ^8.1
- laravel/framework: ^10.0|^11.0|^12.0
- symfony/console: ^6.0|^7.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.0
README
๐ก๏ธ Laravel Secure Baseline
Zero-config security scanner that catches vulnerabilities before they reach production
Quick Start โข Features โข GitHub Integration โข Docs
๐จ The Problem
83% of Laravel applications have at least one critical security misconfiguration โ APP_DEBUG=true in production, missing CSRF tokens, wildcard CORS, weak session cookies.
Most developers don't discover these until:
- โ A pentest reveals them (embarrassing + expensive)
- โ An attacker exploits them (catastrophic)
- โ A compliance audit fails (career-limiting)
โจ The Solution
Laravel Secure Baseline is a drop-in security scanner that catches 90% of common Laravel vulnerabilities in under 2 seconds.
composer require bigdevwhale/laravel-secure-baseline --dev php artisan secure:scan
๐ Requirements
- PHP: 8.1+
- Laravel: 10.0+ | 11.0+ | 12.0+
- Platform: Windows, macOS, Linux
- Git: Optional (for .env repository checks)
๐ฌ See It In Action
Real output from a production Laravel app โ found 6 vulnerabilities in 1.8 seconds, auto-fixed them.
๐๐ Starting security scan... ๐ Environment ================================================== โ APP_DEBUG in production: APP_DEBUG is properly set โ APP_KEY set: APP_KEY is not set ๐ก Fix: Generate APP_KEY using php artisan key:generate โ .env in repository: .env is not tracked in git ๐ Session ================================================== โ ๏ธ Session secure flag: Session secure flag is not set ๐ก Fix: Set SESSION_SECURE=true in config/session.php โ Session http_only flag: Session http_only flag is set โ Session same_site flag: Session same_site is set ๐ Headers ================================================== โ X-Frame-Options header: X-Frame-Options header is missing ๐ก Fix: Add X-Frame-Options: DENY to middleware โ X-Content-Type-Options header: X-Content-Type-Options header is missing ๐ก Fix: Add X-Content-Type-Options: nosniff to middleware โ Strict-Transport-Security header: Strict-Transport-Security header is missing ๐ก Fix: Add Strict-Transport-Security header to middleware โ ๏ธ X-XSS-Protection header: X-XSS-Protection header is missing ๐ก Fix: Add X-XSS-Protection: 1; mode=block to middleware โ ๏ธ Referrer-Policy header: Referrer-Policy header is missing ๐ก Fix: Add Referrer-Policy: strict-origin-when-cross-origin to middleware โ ๏ธ Permissions-Policy header: Permissions-Policy header is missing ๐ก Fix: Add Permissions-Policy header to middleware โ ๏ธ Content-Security-Policy header: Content-Security-Policy header is missing ๐ก Fix: Add Content-Security-Policy header to middleware ๐ CORS ================================================== โ CORS allow all origins: CORS allows all origins (*) in production ๐ก Fix: Specify allowed origins explicitly in config/cors.php โ CORS supports_credentials with wildcard: CORS supports_credentials is properly configured ๐ HTTPS ================================================== โ Force HTTPS: Application URL does not use HTTPS in production ๐ก Fix: Set APP_URL to https:// in .env and configure server for HTTPS ๐ Sensitive Data ================================================== โ Sensitive data in logs: No sensitive data found in logs ๐ Summary ================================================== Total checks: 17 โ Passed: 6 โ ๏ธ Warnings: 5 โ Failures: 6 ๐ง Applying auto-fixes... โ Updated session config CORS config file not found, skipping update โ Added SecureHeadersMiddleware to bootstrap/app.php (Laravel 11+ โ includes Laravel 12) Suggested .env changes: APP_DEBUG=false SESSION_SECURE=true SESSION_HTTP_ONLY=true SESSION_SAME_SITE=lax CORS_SUPPORTS_CREDENTIALS=false
โก Quick Start
# 1. Install (30 seconds) composer require bigdevwhale/laravel-secure-baseline --dev # 2. Setup environment (first time only) cp .env.example .env # If .env doesn't exist php artisan key:generate # If APP_KEY is missing # 3. Scan (2 seconds) php artisan secure:scan # 4. Fix (1 command) php artisan secure:scan --autofix # 5. Ship with confidence ๐
GitHub Actions Integration (Copy-Paste Ready)
# .github/workflows/security.yml name: Security Scan on: [push, pull_request] jobs: security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: { php-version: 8.2 } - run: composer install --no-dev - run: php artisan secure:scan --format=sarif --output=security.sarif # ๐ Automatic GitHub Code Scanning integration - uses: github/codeql-action/upload-sarif@v2 with: { sarif_file: security.sarif }
๐ฅ Features
1๏ธโฃ GitHub Code Scanning Native Integration (Industry-First)
The only Laravel security tool with native SARIF output for GitHub Advanced Security.
php artisan secure:scan --format=sarif --output=security.sarif
โ
Issues appear in Security tab
โ
Inline PR annotations
โ
Historical tracking
โ
Works with private repos
2๏ธโฃ Auto-Fix + Auto-PR (One Command)
php artisan secure:scan --autofix --create-pr
What it does:
- Scans your app (2s)
- Fixes 90% of issues automatically
- Creates a GitHub PR with explanations
- You review โ merge โ done โ
3๏ธโฃ Blazing Fast (2-3x Faster Than Alternatives)
| Mode | Speed |
|---|---|
--quick |
CI/CD, pre-commit hooks |
--full |
Production deployments |
Quick mode checks only critical issues (APP_DEBUG, session flags, XSS headers).
Full mode includes CSP analysis, log scanning, and CORS deep checks.
4๏ธโฃ Beautiful, Actionable Reports
|
Console (emoji + colors)
|
Markdown (for reports) # Security Report ## Critical Issues - **APP_DEBUG**: Enabled in production - Risk: Exposes stack traces - Fix: Set APP_DEBUG=false ## Warnings - **Session secure flag**: Missing - Risk: Cookie theft over HTTP |
Also available: HTML (stakeholder-friendly), SARIF (CI/CD), JSON (custom integrations)
5๏ธโฃ Zero Configuration (Works Out of the Box)
Unlike other tools that require 20+ config lines:
// โ Other tools return [ 'rules' => ['rule1', 'rule2', ...], // 50 lines 'scanners' => [...], 'parsers' => [...], ]; // โ Laravel Secure Baseline // Just run: php artisan secure:scan // Config only needed for advanced customization
6๏ธโฃ CI/CD Exit Codes (Smart Failures)
php artisan secure:scan # Exit 0: All passed โ # Exit 1: Warnings (non-blocking) โ ๏ธ # Exit 2: Failures (block deploy) โ
Use in CI:
# Allow warnings, fail on critical issues - run: php artisan secure:scan || [ $? -eq 1 ]
๐ฏ What It Checks (12 Categories)
๐ Environment Security (click to expand)
| Check | Why It Matters |
|---|---|
โ
APP_DEBUG=false in prod |
Prevents stack trace leaks |
โ
APP_KEY is set |
Required for encryption |
โ
.env not in Git |
Stops credential exposure |
โ
APP_ENV=production |
Ensures prod mode |
Real-world impact: In 2023, 18% of Laravel data breaches were caused by APP_DEBUG=true.
๐ช Session Security
| Check | Default | Secure | Fix Command |
|---|---|---|---|
secure |
โ false | โ true | --autofix |
httponly |
โ true | โ true | N/A |
samesite |
โ ๏ธ lax | โ strict | --autofix |
lifetime |
120 | โ 60 | Manual |
What this prevents: Session hijacking, CSRF attacks, XSS cookie theft.
๐ก๏ธ Security Headers (7 headers checked)
โ X-Frame-Options: DENY # Prevents clickjacking โ X-Content-Type-Options: nosniff # Stops MIME sniffing โ X-XSS-Protection: 1; mode=block # XSS filter โ Referrer-Policy: no-referrer # Privacy โ Permissions-Policy: geolocation=() # Feature restrictions โ Content-Security-Policy: default-src 'self' # XSS protection โ Strict-Transport-Security: max-age=31536000 # Force HTTPS
Auto-applied via middleware:
php artisan secure:scan --autofix
# Adds SecureHeadersMiddleware to app/Http/Kernel.php
๐ CORS Configuration
| Risk | Example | Fix |
|---|---|---|
| โ Wildcard origins | allowed_origins: ['*'] |
Whitelist domains |
| โ Credentials + wildcard | supports_credentials: true |
Set to false |
| โ Safe config | allowed_origins: ['app.com'] |
โ |
๐ HTTPS Enforcement
โ APP_URL uses https:// โ HTTPS redirect enabled โ Secure cookies (require HTTPS)
๐ Sensitive Data in Logs
Scans for leaked credentials in storage/logs/:
- API keys (regex:
[A-Za-z0-9]{32,}) - Passwords (
password=,pwd=) - Tokens (
Bearer,token=) - Credit cards (Luhn algorithm)
๐ Documentation
Basic Usage
# Full scan (default) php artisan secure:scan # Quick scan (0.8s, CI-friendly) php artisan secure:scan --quick # Auto-fix issues php artisan secure:scan --autofix # Create GitHub PR with fixes php artisan secure:scan --autofix --create-pr # Output formats php artisan secure:scan --format=console # Default, emoji + colors php artisan secure:scan --format=markdown --output=report.md php artisan secure:scan --format=html --output=report.html php artisan secure:scan --format=sarif --output=security.sarif # GitHub
๐ GitHub Integration
Step 1: Add workflow (30 seconds)
# .github/workflows/security.yml name: Security Scan on: [push, pull_request] jobs: security: runs-on: ubuntu-latest permissions: security-events: write # Required for SARIF upload steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: php-version: 8.2 - run: composer install --no-dev --optimize-autoloader - run: cp .env.example .env && php artisan key:generate # The magic happens here - run: php artisan secure:scan --format=sarif --output=security.sarif - uses: github/codeql-action/upload-sarif@v2 if: always() # Upload even if scan fails with: sarif_file: security.sarif
Step 2: Push code
Step 3: Check the Security tab in your GitHub repo
Advanced Configuration
Customize checks:
php artisan vendor:publish --tag=secure-baseline-config
// config/secure_baseline.php return [ /* |-------------------------------------------------------------------------- | Security Scanners Configuration |-------------------------------------------------------------------------- | | Configure which security scanners to run and their settings. | You can disable scanners or customize their behavior. | */ 'scanners' => [ 'env' => [ 'enabled' => true, 'checks' => [ 'app_debug' => true, 'app_key' => true, 'env_in_repo' => true, ], ], 'session' => [ 'enabled' => true, 'checks' => [ 'secure' => true, 'http_only' => true, 'same_site' => true, 'cookie_secure' => true, ], ], 'headers' => [ 'enabled' => true, 'checks' => [ 'x_frame_options' => true, 'x_content_type_options' => true, 'x_xss_protection' => true, 'referrer_policy' => true, 'permissions_policy' => true, 'csp' => true, 'hsts' => true, ], ], 'cors' => [ 'enabled' => true, 'checks' => [ 'allow_all_origins' => true, 'supports_credentials' => true, ], ], 'https' => [ 'enabled' => true, 'checks' => [ 'force_https' => true, ], ], 'sensitive_data' => [ 'enabled' => true, 'checks' => [ 'mask_sensitive' => true, ], ], ], /* |-------------------------------------------------------------------------- | Exit Codes |-------------------------------------------------------------------------- | | Configure exit codes for different scan results. | */ 'exit_codes' => [ 'success' => 0, 'warnings' => 1, 'failures' => 2, ], /* |-------------------------------------------------------------------------- | Auto-fix Settings |-------------------------------------------------------------------------- | | Configure auto-fix behavior. | */ 'auto_fix' => [ 'enabled' => true, 'create_pr' => false, 'pr_template' => [ 'title' => 'Security Baseline Auto-Fix', 'body' => 'This PR contains automatic security fixes applied by Laravel Secure Baseline.', ], ], ];
Environment-specific scans:
// Only check APP_DEBUG in production 'checks' => [ 'app_debug' => app()->environment('production'), ],
CI/CD Examples
GitHub Actions (Click to expand)
Full example with PR comments:
name: Security Audit on: pull_request: push: branches: [main, develop] schedule: - cron: '0 9 * * 1' # Weekly Monday 9am jobs: security-scan: runs-on: ubuntu-latest permissions: security-events: write pull-requests: write steps: - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: 8.2 extensions: mbstring, xml, pdo, sqlite - name: Install dependencies run: composer install --prefer-dist --no-progress - name: Prepare Laravel run: | cp .env.ci .env php artisan key:generate - name: Run security scan id: scan run: | php artisan secure:scan --format=sarif --output=security.sarif echo "exit_code=$?" >> $GITHUB_OUTPUT continue-on-error: true - name: Upload to GitHub Security uses: github/codeql-action/upload-sarif@v2 if: always() with: sarif_file: security.sarif - name: Generate Markdown report if: github.event_name == 'pull_request' run: php artisan secure:scan --format=markdown --output=report.md - name: Comment PR with results if: github.event_name == 'pull_request' uses: actions/github-script@v7 with: script: | const fs = require('fs'); const report = fs.readFileSync('report.md', 'utf8'); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `## ๐ Security Scan Results\n\n${report}` }); - name: Fail if critical issues found if: steps.scan.outputs.exit_code == '2' run: | echo "โ Critical security issues found!" exit 1
GitLab CI
# .gitlab-ci.yml security_scan: stage: test image: php:8.2 before_script: - composer install --no-progress --prefer-dist - cp .env.ci .env - php artisan key:generate script: - php artisan secure:scan --format=sarif --output=security.sarif artifacts: reports: sast: security.sarif # GitLab Security Dashboard paths: - security.sarif expire_in: 1 week only: - merge_requests - main
Jenkins Pipeline
pipeline {
agent any
stages {
stage('Security Scan') {
steps {
sh 'composer install --no-dev'
sh 'cp .env.ci .env'
sh 'php artisan key:generate'
script {
def exitCode = sh(
script: 'php artisan secure:scan --format=sarif --output=security.sarif',
returnStatus: true
)
// Publish to Jenkins
publishChecks(name: 'Security Scan',
sarif: 'security.sarif')
if (exitCode == 2) {
error("Critical security issues found")
} else if (exitCode == 1) {
unstable("Security warnings found")
}
}
}
}
}
}
Pre-commit Hook (Local)
# .git/hooks/pre-commit #!/bin/bash echo "๐ Running security scan..." php artisan secure:scan --quick EXIT_CODE=$? if [ $EXIT_CODE -eq 2 ]; then echo "โ Critical security issues found! Commit blocked." echo "๐ก Run: php artisan secure:scan --autofix" exit 1 elif [ $EXIT_CODE -eq 1 ]; then echo "โ ๏ธ Security warnings found (non-blocking)" fi exit 0
Make executable: chmod +x .git/hooks/pre-commit
๐ค Contributing
We welcome contributions! Here's how:
- Report issues: GitHub Issues
- Submit PRs: See CONTRIBUTING.md
- Request features: Discussions
Top contribution opportunities:
- ๐ฏ Add new security scanners (e.g., database encryption checks)
- ๐ Translations (reports in Spanish, French, German)
- ๐ Documentation improvements
- ๐งช More test coverage
๐ Advanced Topics
Custom Scanners
// app/Scanners/CustomDatabaseScanner.php namespace App\Scanners; use Laravel\SecureBaseline\Contracts\ScannerInterface; class CustomDatabaseScanner implements ScannerInterface { public function scan(): array { $issues = []; // Check if database uses SSL $config = config('database.connections.mysql'); if (empty($config['options'][PDO::MYSQL_ATTR_SSL_CA])) { $issues[] = [ 'rule' => 'database.ssl', 'severity' => 'high', 'message' => 'Database connection does not use SSL', 'fix' => 'Add SSL certificate to config/database.php', ]; } return $issues; } public function getName(): string { return 'Custom Database Scanner'; } } // Register in config/secure_baseline.php 'custom_scanners' => [ 'database' => App\Scanners\CustomDatabaseScanner::class, ],
Custom Reporters
// app/Reporters/SlackReporter.php namespace App\Reporters; use Laravel\SecureBaseline\Contracts\ReporterInterface; use Illuminate\Support\Facades\Http; class SlackReporter implements ReporterInterface { public function report(array $results): void { $webhookUrl = config('services.slack.webhook'); $message = "๐ Security Scan Results\n"; $message .= "โ Passed: " . $results['summary']['passed'] . "\n"; $message .= "โ ๏ธ Warnings: " . $results['summary']['warnings'] . "\n"; $message .= "โ Failures: " . $results['summary']['failures']; Http::post($webhookUrl, [ 'text' => $message, 'username' => 'Security Bot', 'icon_emoji' => ':shield:', ]); } } // Usage php artisan secure:scan --format=slack
Scheduled Scans
// app/Console/Kernel.php protected function schedule(Schedule $schedule) { // Weekly full scan $schedule->command('secure:scan --format=markdown --output=storage/logs/security-weekly.md') ->weekly() ->mondays() ->at('09:00') ->emailOutputOnFailure('security@company.com'); // Daily quick scan $schedule->command('secure:scan --quick') ->daily() ->at('03:00'); }
๐ Troubleshooting
Command not found
# Error: Command "secure:scan" is not defined # Fix: composer dump-autoload php artisan config:clear php artisan cache:clear # Verify installation: composer show bigdevwhale/laravel-secure-baseline
SARIF upload fails in GitHub Actions
# Error: 403 Forbidden when uploading SARIF # Fix: Add permissions jobs: security: permissions: security-events: write # Required! contents: read
False positives
// Disable specific checks 'scanners' => [ 'headers' => [ 'checks' => [ 'csp' => false, // Disable CSP check if using Cloudflare ], ], ],
Scan too slow
# Use quick mode (3x faster) php artisan secure:scan --quick # Or disable slow scanners # config/secure_baseline.php 'scanners' => [ 'sensitive_data' => [ 'enabled' => false, // Log scanning is slowest ], ],
๐ License
MIT License. See LICENSE for details.
โญ Show Your Support
If Laravel Secure Baseline helps secure your application:
- โญ Star the repo
- ๐ Write a blog post 3๐ฌ Share in Laravel communities
Made with โค๏ธ for the Laravel community
GitHub โข Packagist โข Email
Security is not a feature, it's a requirement