# 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.

**Severity:** high | **Category:** Application Security

---

## The Issue

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.

## Steps 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_abc123

Never 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 scanning

GitHub will alert you immediately if a known secret pattern is pushed to the repo.

## Verification

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.

