whiteweb.security / guides / Laravel log exposed
/storage/logs/laravel.log Critical — credentials in log ~5 min read

My Laravel log file is publicly accessible. What should I do?

Laravel writes detailed error logs to storage/logs/laravel.log. When database connections fail or exceptions are thrown, those messages often include the full DSN — database host, username, and password — in plain text. If the file is reachable from the internet, those credentials are too.

First: block the path, then rotate every credential in the log.

The log is readable right now. Close the access first, then assume everything in it was read. Check the full file — logs grow; what leaked may be weeks of errors.

// the 60-second version

  • Block /storage/logs/ in your web server config or move storage out of the web root.
  • Read the log carefully — rotate every credential you find.
  • Fix the underlying error so credentials stop spilling into the log.
  • Review access logs to see who downloaded the file.

01Why credentials end up in the log

Laravel catches unhandled exceptions and writes them with full context. When a database connection fails, the PDO exception message includes the DSN — which contains the host, port, username, and often the password:

typical leaked PDO errorlaravel.log
[2025-03-14 08:22:11] local.ERROR: SQLSTATE[HY000] [2002] Connection refused
  (Connection: mysql, SQL: ...)
  PDOException with message 'SQLSTATE[HY000] [1045] Access denied
  for user 'db_user'@'localhost' (using password: YES)'
  "url": "mysql://db_user:p@ssw0rd@127.0.0.1:3306/myapp"

Other common sources of leaked secrets in logs:

  • Mail configuration errors — SMTP password visible in connection exception.
  • API call failures — request headers (with Authorization: Bearer …) logged on HTTP error.
  • Queue/cache connection errors — Redis or SQS credentials in DSN.
  • Verbose debug logging — stack traces that dump full request context including env values.

Laravel rotates log files daily by default, so laravel.log may only show today’s errors. Check for laravel-2025-03-13.log and similar date-stamped files in the same directory — all of them are potentially readable.

02Block the path immediately

Laravel’s storage/ directory should never be web-accessible. The correct fix is to make sure your web root points to the public/ subdirectory, not the project root:

correct document rootnginx
root /var/www/myapp/public;  # NOT /var/www/myapp

If you can’t change the document root right now, block the path explicitly:

deny storage/ in nginxnginx.conf
location ~* ^/storage/ {
    deny all;
    return 404;
}
deny storage/ in Apache.htaccess
RedirectMatch 404 ^/storage/

Laravel ships with a public/.htaccess that blocks access to everything outside public/. If you’re on Apache and the web root is set correctly, this already protects you.

03Read the log and rotate every credential

Download the log and read it carefully before rotating anything — you need to know what was in it. Look for:

  • Database DSN strings (contain username and password)
  • SMTP credentials
  • API keys or bearer tokens in request headers
  • Redis/Memcache/SQS connection strings
  • Any value from your .env that was logged in a stack trace

Rotate each one. For database passwords and API keys, change them at the source and update your .env. For tokens (OAuth, API keys), revoke the old ones and issue new ones.

04Stop credentials spilling into logs

After rotating, fix why they got there in the first place:

  • Database connection failures — check your DB_HOST, DB_PORT, firewall rules. A connection that keeps failing keeps logging.
  • Reduce exception verbosity in production — set APP_DEBUG=false in .env. With debug off, Laravel doesn’t include full stack traces with context in the log.
  • Use a log sanitizer — Laravel’s $dontFlash array on exception handlers can suppress sensitive request values from logs.
suppress sensitive fields from logged requestsapp/Exceptions/Handler.php
protected $dontFlash = [
    'current_password',
    'password',
    'password_confirmation',
    'token',
    'api_key',
];

05Check who accessed the file

Review your web server access logs for requests to the log path:

find log access in nginx/Apache logsbash
grep -E "storage/logs/laravel" /var/log/nginx/access.log

A 200 response on a large file from an unknown IP is a strong indicator the log was downloaded. Note the IPs and check whether access correlates with any suspicious database activity or unusual API usage.

06Make sure it can’t happen again

  • Always point the web root at public/, not the project root. This is the most important protection.
  • Set APP_DEBUG=false in production — this reduces what ends up in the log.
  • Keep storage/ out of version control — add storage/logs/ to .gitignore so logs don’t accidentally end up in repositories either.
  • Use a secrets manager — if credentials are injected at runtime via environment variables rather than stored in .env files, a leaked log has far less impact.

Was this guide useful?

These playbooks are free to read and share. If a heads-up ever saved you a bad week, you can say thanks — or jump into the other guides.