psalm/plugin-laravel
Laravel Psalm plugin for deep static analysis plus taint-based security scanning. Detects SQL injection, XSS, SSRF, shell injection, path traversal, and open redirects by tracking user input through Laravel code without running it.
Emitted when env() is called outside the application's config directory (by default the booted app's config_path(); configurable via <configDirectory> for non-standard layouts).
When you run php artisan config:cache, Laravel loads all config files once and caches the result.
After that, the .env file is not loaded — so any env() call outside config/ returns null.
This is a documented Laravel behavior:
You should be confident that you are only calling the
envfunction from within your configuration files. [...] If you cache your configuration, theenvfunction will only returnnull.
// Bad — will return null when config is cached
class PaymentService
{
public function getKey(): string
{
return env('STRIPE_SECRET'); // NoEnvOutsideConfig
}
}
// Good — read env in config, use config() elsewhere
// config/services.php
return [
'stripe' => [
'secret' => env('STRIPE_SECRET'),
],
];
// app/Services/PaymentService.php
class PaymentService
{
public function getKey(): string
{
return config('services.stripe.secret');
}
}
env() call into a config file (e.g. config/services.php)config() in your application codeBy default the plugin treats only the Laravel app's config_path() as a config directory. If your project keeps configuration elsewhere (for example BookStack's app/Config/) or you want to allow env() inside vendor packages, add <configDirectory> elements to your psalm.xml:
<pluginClass class="Psalm\LaravelPlugin\Plugin">
<configDirectory name="app/Config" />
<configDirectory name="packages/*/config" />
</pluginClass>
See Configuration for the full reference.
How can I help you explore Laravel packages today?