Introduction

When Apache's Options Indexes directive is enabled, visiting a directory URL without an index file (like index.html) displays a listing of all files in that directory. This can expose sensitive files including .env configuration files, .git repositories, database backups, and application source code. A simple test confirms the issue:

bash curl -s http://example.com/uploads/ | grep -c "<a href" `` If the count is greater than 0 and shows file listings, directory listing is enabled.

Symptoms

  • Browsing to a directory URL shows a file listing instead of a 403 Forbidden error
  • Sensitive files (.env, .git/, config/, backups/) are visible to anyone
  • Search engine indexes reveal directory contents
  • Security scanners flag "Directory Indexing" vulnerability
  • .git/HEAD or .git/config accessible at http://example.com/.git/config

Common Causes

  • Options Indexes set in the main Apache configuration or VirtualHost
  • Default Apache configuration on Debian/Ubuntu includes Options Indexes FollowSymLinks
  • .htaccess file overrides the server-level directive to enable indexing
  • Application installer scripts add Options Indexes for upload directories
  • Configuration inherited from parent directory context

Step-by-Step Fix

  1. 1.Disable directory listing at the server or VirtualHost level:
  2. 2.```apache
  3. 3.<Directory /var/www/html>
  4. 4.Options -Indexes +FollowSymLinks
  5. 5.AllowOverride None
  6. 6.Require all granted
  7. 7.</Directory>
  8. 8.`
  9. 9.The -Indexes prefix explicitly disables directory listing even if a parent directory enables it.
  10. 10.Block access to hidden files and sensitive directories:
  11. 11.```apache
  12. 12.# Block all hidden files (starting with .)
  13. 13.<DirectoryMatch "/\.">
  14. 14.Require all denied
  15. 15.</DirectoryMatch>

# Block specific sensitive file types <FilesMatch "^\."> Require all denied </FilesMatch>

# Block .git directories specifically <DirectoryMatch "/\.git"> Require all denied </DirectoryMatch> ```

  1. 1.Block access to common sensitive files explicitly:
  2. 2.```apache
  3. 3.<FilesMatch "\.(env|sql|bak|old|orig|save|swp|dist|config|ini)$">
  4. 4.Require all denied
  5. 5.</FilesMatch>
  6. 6.`
  7. 7.Remove index files that enable directory browsing in specific locations:
  8. 8.```apache
  9. 9.# For upload directories, only disable indexing, not access
  10. 10.<Directory /var/www/html/uploads>
  11. 11.Options -Indexes
  12. 12.AllowOverride None
  13. 13.Require all granted
  14. 14.</Directory>
  15. 15.`
  16. 16.Verify the fix by testing common paths:
  17. 17.```bash
  18. 18.curl -s -o /dev/null -w "%{http_code}" http://example.com/uploads/
  19. 19.# Should return 403

curl -s -o /dev/null -w "%{http_code}" http://example.com/.git/config # Should return 403

curl -s -o /dev/null -w "%{http_code}" http://example.com/.env # Should return 403 ```

Prevention

  • Start all new configurations with Options -Indexes as the default
  • Include sensitive file blocking rules in your base Apache configuration template
  • Run periodic security scans with tools like Nikto or Nuclei to detect directory listing
  • Add directory listing checks to your CI/CD pipeline: curl -sf http://staging/uploads/ | grep "Index of" && exit 1
  • Use mod_security rules to automatically block requests to .env, .git/, and other sensitive paths
  • Document the expected directory listing configuration for each virtual host in your runbook
  • After deploying changes, manually test directory URLs with a browser and curl