Webroot hygiene and error display: two things that leak
Archives and backups left in the webroot can be downloaded by anyone, and OpenCart errors can print the database password on the storefront.
Two checks that take minutes and close real holes. Look for them on every shop you touch.
Files that should not be there
find $W -maxdepth 1 \( -name '*.sql' -o -name '*.zip' -o -name '*.tar.gz' \
-o -name '*.bak' -o -name '*.old' \)
Extension archives and .htaccess.bak files can be downloaded by anyone who guesses the address. A backup of .htaccess reveals the server configuration. Typical finds: extension installers (*.ocmod.zip) and a copy of .htaccess saved before an edit.
Error display is the database password on the storefront
When the connection to the database fails (for example, max_user_connections is reached), OpenCart 2.x throws an exception. The stack trace contains DB\MySQLi->__construct('localhost', '<user>', '<password>', ...). With display_errors on, every visitor sees that line.
Switch off both layers:
- PHP:
display_errors Off, and an error log outside the webroot. Check the effective value; a configuration block generated by a control panel can be ignored by the web server. - OpenCart:
config_error_display = 0. Its own handler prints warnings and notices regardless ofdisplay_errors.
Reading error logs
uniq -c on whole lines prints the stack arguments together with the password. Count by a prefix of the line, not by the whole line. Any password you find in a log should be treated as compromised and changed.
See also: Language folders and hreflang.