Hardcoded Credentials in Laravel: How to Find and Remove Secrets from Source Code
API keys, passwords, and secrets committed to source code are exposed to anyone with repository access. Move them to environment variables before they leak.
Hardcoded credentials are passwords, API keys, private keys, and other authentication material embedded directly in source code files. Developers hardcode credentials for convenience — it removes the friction of environment configuration during initial development — but the habit becomes a security liability the moment the code is committed to version control.
Git's append-only history model means credentials committed to a repository persist forever in the commit log, even after the file is updated to remove them. Attackers use automated tools like truffleHog, gitleaks, and GitHub's built-in secret scanning to search every commit in a repository's history for patterns matching API keys, passwords, and private keys. For public repositories, these scans happen within minutes of every push. For private repositories, credentials exposed to any employee or contractor become a long-term risk.
The scale of the problem is significant. Security researchers regularly find millions of active credentials in public GitHub repositories. Cloud providers like AWS have automated systems that detect their own API keys in public repositories and alert account owners within seconds. Despite this awareness, new hardcoded credentials appear constantly — often in configuration files, test suites, and seed data. The fix is straightforward: use .env files for all credentials, ensure .env is in .gitignore, and add pre-commit hooks to prevent future commits.
The Problem
Hardcoded credentials — API keys, database passwords, encryption keys, SMTP passwords, and third-party secrets embedded directly in PHP files — are one of the most common security findings in Laravel projects. Once committed to Git, these secrets exist in the repository history permanently, even if deleted later. Anyone with read access to the repo can extract them. Automated bots scan public repositories for credentials continuously.
How to Fix
-
1
Find hardcoded secrets in your codebase
Search for common patterns:
grep -rn 'password.*=.*["'\']' app/ config/ --include='*.php' grep -rn 'api_key\|api_secret\|secret_key\|access_token' app/ --include='*.php' grep -rn 'sk_live\|pk_live\|sk_test\|AKIA' app/ config/ --include='*.php'Also check for base64-encoded keys and connection strings with embedded credentials.
-
2
Move secrets to .env and config files
Replace hardcoded values with environment variable references:
// BEFORE — hardcoded in a service class $client = new StripeClient('sk_live_abc123');// AFTER — from environment $client = new StripeClient(config('services.stripe.secret'));// config/services.php 'stripe' => [ 'secret' => env('STRIPE_SECRET'), ],// .env STRIPE_SECRET=sk_live_abc123Never commit .env to version control. Ensure .env is in your .gitignore.
-
3
Rotate any exposed credentials immediately
If credentials were ever committed to Git, they are compromised even if the commit is deleted:1. Regenerate every exposed API key, password, and secret 2. Update the new values in your production .env 3. Revoke the old credentials at the provider (Stripe, AWS, etc.) 4. Check Git history: git log --all -p -S 'sk_live' to find exposure 5. Consider using git-filter-repo to remove secrets from history if the repo is public -
4
Add secret scanning to your workflow
Prevent future commits of secrets:
# Install gitleaks as a pre-commit hook brew install gitleaks gitleaks detect --source . --verbose# Or use GitHub's built-in secret scanning # Enable in repo Settings > Code security and analysis > Secret scanningGitHub will alert you immediately if a known secret pattern is pushed to the repo.
How to Verify
Run the scanner:
php artisan stackshield:scan --check=SS008
Manually verify:
grep -rn 'password\|secret\|api_key' app/ config/ routes/ --include='*.php' | grep -v 'env(\|config(\|#\|//'
Any results that contain literal secret values need to be moved to .env.
Prevention
Add .env to .gitignore (Laravel does this by default). Use a pre-commit hook with gitleaks or similar. Enable GitHub secret scanning. Never log or dump credentials in error handlers. Use StackShield to scan for hardcoded secrets continuously.
Frequently Asked Questions
Is it safe to hardcode credentials in config files?
No. Config files are committed to Git just like any other source file. Always use env() in config files and keep actual values in .env. The only exception is non-sensitive defaults like env('CACHE_DRIVER', 'file').
What if I need to share credentials with my team?
Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, 1Password) or a secure .env sharing tool like Laravel Envoyer, Doppler, or a team password manager. Never share credentials via Slack, email, or Git.
If I deleted a credential from my code and pushed, is it still at risk?
Yes. Git preserves all history including deleted content. Run git log --all -p -S "your_secret" to see every commit where the credential appeared. If the repository was ever public, the credential is permanently compromised and must be rotated regardless of deletion. Treat any credential that was ever in a Git commit as exposed.
Should I call env() directly in service classes or always go through config()?
Always go through config(). Calling env() directly in service classes breaks when config:cache is active because cached configuration bypasses .env parsing. Define your secrets in a config file using env("STRIPE_SECRET") and reference them as config("services.stripe.secret") throughout your application code.
How do I scan my existing Git history for committed secrets?
Run gitleaks detect --source . --log-opts="--all" to scan all commits across all branches. The open-source tool truffleHog also works well for pattern-based secret detection. After scanning, rotate every exposed credential immediately, even if the commits are old or from deleted branches — the history is still accessible.
Related Guides
Laravel .env File Exposed: How to Block Public Access and Rotate Leaked Credentials
Your Laravel .env file is publicly accessible, leaking database credentials, APP_KEY, and API keys. Block it in Apache and Nginx, then rotate every compromised secret.
How to Fix an Exposed .git Directory
Your .git directory is publicly accessible, allowing attackers to download your entire source code and commit history. Fix it now.
Laravel APP_KEY Security: How to Generate, Rotate, and Protect Your Encryption Key
A missing, short, or committed APP_KEY compromises session encryption, signed URLs, and all data encrypted with Crypt. Generate a strong key and keep it out of Git.
Is your Laravel app exposed right now?
34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.