Hosting Autopsy / The database backup left in the public folder

The database backup left in the public folder

HOSTING AUTOPSY

6 min read · 1,289 words

This is a composite case written by the editors. It is built from patterns that come up often in support work and is not the account of a particular named person or company.

A freelancer made a quick database export before an update and saved it as backup.sql in the site's public folder, because it was convenient. He meant to delete it afterwards and forgot.

Automated scanners look for exactly this kind of file. Within weeks, the server logs showed repeated requests for common backup filenames, and one of them succeeded. The file contained user records with hashed passwords and email addresses.

The client had to notify its users, reset every password and review its obligations. A single forgotten file turned a routine update into a month of cleanup. The client here was a small membership organisation, and the story is a composite of several incidents with the same ingredients: a convenient location, a predictable name and a delay.

Why the public folder was the convenient place

The freelancer worked over a file manager and a browser-based database tool. His routine before an update was to export the database, then download the export to his laptop. On shared hosting, exports made by the database tool are often written to the account's web directory, and the download link points straight at them. The file manager showed the same folder as the site itself, so putting the file in the top-level public folder meant it was one click away.

That folder, often called public_html or htdocs, is special: everything in it can be fetched by anyone who guesses its name. There is no login in front of a plain file. If the web server is willing to serve a .php file by running it, it is equally willing to serve a .sql file by sending it. Web servers do not know a backup from a stylesheet.

The update went well. The freelancer closed the tab and went to the next job. On his task list the line "remove backup" sat under a heading marked "later".

Hosting account (home directory)private/not reachable by URLbackups belong herepublic_html/anyone can fetch filesbackup.sql was here
Only one of the two folders is served by the web server, and the backup went in that one.

How scanners found it

Nobody linked to the file. It was not in the sitemap and it did not appear in the site's menus. It did not need to. A large share of the traffic any public server receives is automated: programs that work through lists of common filenames and ask for each one, indefinitely. Among the names on those lists are backup.sql, db.sql, dump.sql, site.zip, www.tar.gz, .env and many variations with years and domain names.

The logs afterwards told the story plainly. Lines like these were scattered through the access log over several weeks:

198.51.100.23 - - [12/Mar/2026:03:14:07 +0000] "GET /backup.sql HTTP/1.1" 404 196
198.51.100.23 - - [12/Mar/2026:03:14:08 +0000] "GET /db.sql HTTP/1.1" 404 196
203.0.113.77  - - [29/Mar/2026:19:42:51 +0000] "GET /backup.sql HTTP/1.1" 200 48211337

The first two are misses, and most of the time the answer is 404. The last is a hit, with a 200 status and a response size of about 46 megabytes. After that single line the data was no longer under the client's control, and there is no way to unsend it.

The timing is typical. The file sat for weeks before the first successful request, which gave a false sense of safety. A scanner may not return for a long time; it may also come back twice in a day.

Day 0file savedWeeks 1-3scans, mostly 404One 200file downloadedLaterfound in the logsIllustrative timing
The exposure lasted until someone looked, not until the scanner arrived.

The window of exposure

The file was reachable from the day it was saved until the day it was removed, and everything in between counts. The success was not the start of the problem; it was only the moment the problem became visible. Anyone reading the logs afterwards has to assume that other copies may have been taken earlier by clients that did not log in any recognisable way, for instance through a caching proxy or a download that the server logged under another address.

This is why the recommended response begins with the clock. The sooner the file is gone, the smaller the window, and the more precise the notice to users can be about what was exposed and when. A vague timeline means a wider notice and more passwords reset than strictly necessary.

What was in the file

A full database export contains everything the application stores. For a membership organisation that meant names, email addresses, postal addresses, membership numbers, the text of messages between members, and a table of users with password hashes.

Hashes are not passwords, but they are not nothing either. A well-chosen modern hash protects strong passwords well. An old, fast hash such as unsalted MD5 protects weak passwords poorly, since a determined attacker can try billions of guesses a second offline. In this case the site used the application's standard scheme, which was better than average, but a share of the members used short or common passwords.

The export also included the application's own settings table. That held the addresses and keys of outside services, such as the mail provider. Those secrets had to be rotated as well.

The response, week by week

The discovery was accidental: the client's webmaster saw the 200 while checking the logs for something unrelated. From then on, the order of work was this.

  1. Remove the file and confirm that the address now returns 404. This takes a minute and should be done first.
  2. Establish exactly when the file existed and which requests succeeded, using the access logs. That gave a window and a small number of source addresses.
  3. Force a password reset for all users, and invalidate existing sessions.
  4. Rotate every secret that was in the database: mail keys, payment gateway tokens, API tokens.
  5. Tell the affected people, plainly, what was exposed and what they should do. Because personal data was involved, the organisation also reviewed its legal obligations, including whether the regulator had to be told within the deadline that applies in its country.
  6. Watch for abuse: phishing aimed at members, and login attempts using the exposed email addresses with passwords from other leaks.

None of this was dramatic, and all of it took time. Replies from members arrived for weeks. A fraction were angry; most were practical. The one thing that helped was the organisation's frankness in the first message.

The fix that lasts

Deleting the file stopped the leak but did not remove the cause. The cause was a habit, plus a server willing to serve any file at all. Three changes dealt with both.

First, backups moved out of the public folder altogether. On most hosting accounts a folder above the public one, in the home directory, is not served. A command-line export to there looks like this:

mysqldump --single-transaction -u dbuser -p dbname | gzip > ~/private/backups/dbname-$(date +%F).sql.gz

Second, the web server was told to refuse downloads of risky extensions even if one is dropped into the public folder by mistake. For Apache, an .htaccess rule does it:

<FilesMatch "\.(sql|bak|old|zip|tar|gz|env|log)$">
  Require all denied
</FilesMatch>

On nginx the equivalent is a location ~* \.(sql|bak|zip|gz|env)$ { deny all; } block.

A deny rule is a second line of defence, not permission to be careless. It will not help if the file has an unusual name or extension, or if a rule is accidentally overridden by a later configuration change.

Third, the freelancer's checklist gained a line he could not ignore: a recurring reminder, the same day, to list the public folder and remove anything he had put there.

What would have caught it

PreviousThe launch-day database that ran out of connectionsNextThe auto-reply that answered itself eleven thousand times

More from Hosting Autopsy

Autopsy

The sale that started at the wrong hour

A retailer scheduled a flash sale for 9 a.m. The shop software was set to the store's local time. The...

Autopsy

The backup that could not be restored

A hobbyist forum had a nightly backup running faithfully for over a year. Every morning the control panel...

Autopsy

The image that cost a month's hosting

A photographer on a pay-by-usage cloud plan published a picture that was picked up by a popular forum. People...