Why a leftover backup.sql is the worst file on your server
One forgotten SQL dump is every customer record, no hacking required.
A leaked API key is bad because of what someone can do with it. A leaked backup.sql is worse because there's nothing left to do. The data is already in the file. There's no database connection to make, no auth to bypass, no query to run. Someone downloads a file and they have everything your database held the moment that dump was taken.
Why a single file is the entire breach
Think about what a mysqldump or pg_dump actually produces. It's a plaintext file containing CREATE TABLE statements followed by INSERT statements for every row. Your users table, with emails and password hashes. Your orders table, with names and addresses. Your payments table. Your sessions, your API tokens, your internal notes. All of it, serialized into one file, in the clear.
Normally that's fine because the dump lives somewhere private and gets shipped to backup storage. The danger is the copy that doesn't move. The one a person made by hand, during an incident or a migration, and left sitting in a directory that happens to be served to the web.
How it gets to the web root
Nobody plans to publish a database dump. It happens during the messy moments. You're debugging a production issue and you run mysqldump app > backup.sql in whatever directory you happen to be in, which turns out to be the web root. You're migrating hosts and you stage the dump where the deploy can reach it, then forget the deploy directory is also the public directory. A cron job writes a nightly dump.sql into a folder you assumed was private.
The filenames are the giveaway, and they're depressingly predictable: backup.sql, dump.sql, database.sql, db.sql, backup.zip, backup.tar.gz, www.zip. Crawlers carry a wordlist of exactly these names and try them against every site. The same misconfiguration that can expose your .env file exposes these too, because they're all just files sitting in a directory the server will hand to anyone who asks for them by name.
What's actually at risk
The password hashes are the part people wave off. They're hashed, so they're safe, right? Only partly. If you used a fast hash like MD5 or unsalted SHA-1, those crack on a single GPU at enormous speed. Even a slow hash like bcrypt protects only the weak passwords; the reused ones get matched against existing breach databases. And every email in that file is now a target for credential stuffing somewhere else.
The rest of the dump needs no cracking at all. Names, addresses, order history, support tickets, internal flags, API tokens stored in plaintext columns, session identifiers. That's a privacy incident and, depending on where your users live, a reportable one under GDPR or similar. It also took the attacker exactly one HTTP request, which means there's no intrusion to detect. Your logs show a file download. That's it.
Finding it before a bot does
You can check this from the outside in a couple of minutes, and you should, because the people who write these files are the same people who'd never think to request them afterward.
Walk the common names by hand against your domain:
https://yoursite.com/backup.sqlhttps://yoursite.com/dump.sqlhttps://yoursite.com/database.sqland/db.sqlhttps://yoursite.com/backup.zip,/backup.tar.gz,/www.zip
A 404 on all of them is the result you want. A 200, especially with a large Content-Length, means the file is downloadable right now and you should treat the data in it as already gone.
If you find one, delete it, then move backups out of any web-served directory entirely and send them to object storage with no public access. Add a server rule that refuses these extensions outright, so the next hand-made dump can't be served even if someone drops it in the wrong place.
# nginx: any file in the web root is fair game
location / {
try_files $uri =404;
}
# /backup.sql, /dump.sql, /www.zip all return 200The good news in all of this is how cheap the check is. Whether a dump is downloadable is decided entirely by what your server hands out, so you can find out the same way a crawler would, without going anywhere near your database. SurfaceCheckr runs the common dump and archive names against your domain from outside and tells you which, if any, come back with content. It never opens the file or reads a single row, and it isn't a pentest of your app. It answers one question: is the worst file on your server sitting there with the door open.
Find it before someone else does.
Paste your domain. The grade and issue count are free, and you'll see in a couple of minutes exactly what's reachable from outside.