All guides
Critical severityMisconfigurations

Exposed database backups: what happens when /backup.sql is reachable

Database backups — .sql files, compressed dumps, zip archives of the database — are sometimes created directly in a web-accessible directory and left there. A single successful request to /backup.sql or /dump.sql hands an attacker every row of every table without touching your application logic.

What it is

Backup scripts, hosting control panels, and manual export tools commonly write dump files with predictable names: backup.sql, dump.sql, database.sql, db.sql.gz, backup.zip. When these land inside the web root and the server doesn't explicitly block them, they become ordinary downloadable files. Attackers run automated scans that request dozens of these common names against every host they can reach.

AppSafe checks for the most common paths — /backup.sql, /dump.sql, /database.sql, /db.sql.gz, and others — and flags any that return a 200 response with content that looks like a SQL dump or archive. The check catches both plain-text SQL and compressed formats.

Why it matters

A SQL dump contains every row in every table at the time it was taken: user accounts, password hashes, email addresses, PII, session tokens, payment history, and internal application state. Downloading a dump is a single HTTP request that leaves no trace in your application logs — the web server serves it like any static file.

Unlike a leaked API key, you can't rotate a leaked database. Once someone has a copy of your users table, the breach is permanent for those users. Depending on what the dump contains, you may face mandatory breach notifications under GDPR, CCPA, or HIPAA, along with the operational cost of notifying every affected user.

How to fix it

Move backups outside the web root

The correct fix is to write backup files to a directory the web server can't reach — a path like /var/backups/ or an object-storage bucket with private ACLs, not a subdirectory of /var/www/. Review any cron jobs or backup scripts and update the target path.

Block common backup extensions in nginx

As a defence-in-depth measure, deny requests for SQL files and common archive extensions at the server level, regardless of where files are stored.

location ~* \.(sql|sql\.gz|bak|dump|tar|tar\.gz|tar\.bz2|zip)$ {
  deny all;
  return 404;
}
Delete any dump files already in the web root

If you find an exposed file, delete it immediately. Then audit how it got there — fix the script or process that placed it, so it doesn't reappear on the next scheduled run.

Verify the paths return 404

After cleaning up, confirm the common paths are blocked.

for path in /backup.sql /dump.sql /database.sql /db.sql.gz; do
  code=$(curl -so /dev/null -w "%{http_code}" "https://yourdomain.com$path")
  echo "$path → $code"
done
# Every line must print 404

FAQ

How would an attacker know to try /backup.sql on my site?

They don't target you specifically. Automated scanners request dozens of common backup names against millions of hosts continuously. A file that exists returns 200 and gets downloaded before you'd know to look.

The file was only there for an hour. Is the damage done?

Possibly. Automated scans run around the clock and files are often found within minutes of appearing. If you have access logs, check whether the path was requested — if it was, treat it as a confirmed breach.

Can I just password-protect the file instead of moving it?

Basic auth on a single file is fragile and easy to misconfigure. The right answer is to remove the file from any web-accessible location entirely. Backups should live somewhere the HTTP server cannot reach.

Is your app affected?

AppSafe checks for this and dozens of other issues in one free scan.

Scan my app free