paulohps / laravel-csw
A Laravel package to monitor Composer dependencies for security vulnerabilities
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0||^10.0||^11.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
README
Automate composer audit in your Laravel application and receive vulnerability alerts via Log, Slack, Discord, Email, or Database — on a schedule or on demand.
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.3 |
| Laravel | ^11.0 | ^12.0 | ^13.0 |
| Composer | ^2.4 (for audit command support) |
Installation
Install the package via Composer:
composer require paulohps/laravel-csw
Publish the configuration file:
php artisan vendor:publish --tag="composer-security-watch-config"
Configuration
The published config file is located at config/composer-security-watch.php.
return [ 'enabled' => env('CSW_ENABLED', true), 'schedule' => [ 'frequency' => env('CSW_SCHEDULE_FREQUENCY', '0 9 * * *'), ], 'notify' => [ // Job responsible for dispatching notifications. // Override 'class' for custom dispatch logic; set 'queue' to target a specific queue. 'job' => [ 'class' => \LaravelCsw\Jobs\SendVulnerabilityNotificationsJob::class, 'queue' => env('CSW_JOB_QUEUE', 'default'), ], 'channels' => [ 'log' => [ 'enabled' => env('CSW_NOTIFY_LOG', true), 'class' => \LaravelCsw\Channels\LogChannel::class, ], 'slack' => [ 'enabled' => env('CSW_NOTIFY_SLACK', false), 'class' => \LaravelCsw\Channels\SlackChannel::class, 'webhook_url' => env('CSW_SLACK_WEBHOOK_URL'), ], 'discord' => [ 'enabled' => env('CSW_NOTIFY_DISCORD', false), 'class' => \LaravelCsw\Channels\DiscordChannel::class, 'webhook_url' => env('CSW_DISCORD_WEBHOOK_URL'), ], 'email' => [ 'enabled' => env('CSW_NOTIFY_EMAIL', false), 'class' => \LaravelCsw\Channels\EmailChannel::class, 'to' => env('CSW_EMAIL_TO'), 'mailable' => \LaravelCsw\Mail\VulnerabilityReport::class, ], 'database' => [ 'enabled' => env('CSW_NOTIFY_DATABASE', false), 'class' => \LaravelCsw\Channels\DatabaseChannel::class, ], ], ], ];
Available environment variables
| Variable | Description |
|---|---|
CSW_ENABLED |
Enable/disable the package (true) |
CSW_SCHEDULE_FREQUENCY |
Cron expression for scheduled audit (0 9 * * *) |
CSW_NOTIFY_LOG |
Enable log channel (true) |
CSW_NOTIFY_SLACK |
Enable Slack channel (false) |
CSW_SLACK_WEBHOOK_URL |
Slack incoming webhook URL |
CSW_NOTIFY_DISCORD |
Enable Discord channel (false) |
CSW_DISCORD_WEBHOOK_URL |
Discord webhook URL |
CSW_NOTIFY_EMAIL |
Enable email channel (false) |
CSW_EMAIL_TO |
Recipient email address(es) |
CSW_NOTIFY_DATABASE |
Enable database channel (false) |
CSW_JOB_QUEUE |
Queue name for the notification job (default) |
Usage
Artisan Command
Basic audit:
php artisan csw:audit
Returns exit code 0 when clean, 1 when vulnerabilities are found — useful in CI pipelines.
Audit + send notifications:
php artisan csw:audit --notify
Dispatches SendVulnerabilityNotificationsJob which sends alerts to all enabled channels.
Audit + update vulnerable packages:
php artisan csw:audit --update
Runs composer update vendor/package for each affected package.
Audit + update including all dependents:
php artisan csw:audit --update --with-all
Passes --with-all-dependencies to composer update. Requires --update.
Scheduled Audit
When enabled is true, CSW automatically registers a scheduled command at the configured cron frequency. Make sure your Laravel scheduler is running:
# Add to crontab * * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1
The scheduled command runs: php artisan csw:audit --notify
Notification Channels
Log (default: enabled)
Writes a warning log entry for each vulnerability. Uses your application's default log channel.
Slack
Set up a Slack Incoming Webhook and add the URL to your config or .env:
CSW_NOTIFY_SLACK=true CSW_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
Discord
Create a webhook via Server Settings > Integrations > Webhooks:
CSW_NOTIFY_DISCORD=true CSW_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy
Supports single address or an array of addresses:
CSW_NOTIFY_EMAIL=true CSW_EMAIL_TO=security@example.com
For multiple recipients, set in config/composer-security-watch.php:
'email' => [ 'enabled' => true, 'to' => ['admin@example.com', 'security@example.com'], ],
To customise the email subject, headers, or template, override the mailable key with your own Mailable class. Its constructor must accept array $vulnerabilities as the first argument:
'email' => [ 'enabled' => true, 'to' => env('CSW_EMAIL_TO'), 'mailable' => \App\Mail\MyVulnerabilityReport::class, ],
Database
The database channel requires a migration. Install it with:
php artisan csw:install-database-channel php artisan migrate
Then enable it:
CSW_NOTIFY_DATABASE=true
Vulnerabilities are stored in the composer_security_vulnerabilities table, accessible via the VulnerabilityRecord model:
use LaravelCsw\Models\VulnerabilityRecord; VulnerabilityRecord::latest('found_at')->get();
Custom Notification Channels
Implement LaravelCsw\Contracts\NotificationChannel to create your own channel:
use LaravelCsw\Contracts\NotificationChannel; use LaravelCsw\Data\Vulnerability; class PagerDutyChannel implements NotificationChannel { public function send(array $vulnerabilities): void { foreach ($vulnerabilities as $vulnerability) { // Send to PagerDuty... } } }
Register it in the notify.channels config array — the class key is what the notification job uses to resolve the channel:
'notify' => [ 'channels' => [ // ... existing channels ... 'pager_duty' => [ 'enabled' => true, 'class' => \App\Channels\PagerDutyChannel::class, ], ], ],
You can also override a built-in channel by binding your own implementation in a service provider:
// In AppServiceProvider::register() $this->app->bind( \LaravelCsw\Channels\SlackChannel::class, \App\Channels\CustomSlackChannel::class, );
The Vulnerability Object
Notification channels receive an array of LaravelCsw\Data\Vulnerability objects:
readonly class Vulnerability { public string $packageName; public string $version; public string $advisoryId; public string $title; public ?string $link; public ?string $cve; }
Docker (local development)
A Docker environment is provided for running PHP and Composer without a local installation:
# Build the image docker compose build # Install dependencies docker compose run --rm app composer install # Run tests docker compose run --rm app vendor/bin/pest # Run audit docker compose run --rm app php artisan csw:audit
Testing
# Run all tests composer test # Run tests with coverage report (requires 100%) composer test-coverage # Apply code style composer format
Changelog
Please see CHANGELOG.md for recent changes.
Contributing
Please see CONTRIBUTING.md for details.
License
The MIT License (MIT). Please see License File for more information.