The Password Was Literally in a Text File

Sherlock Forensics shares an anonymized composite war story from penetration testing engagements. The database password was found in a publicly accessible text file within 4 minutes of starting the assessment. Each subsequent finding was worse than the last, escalating from exposed credentials to full system compromise with access to customer financial data.

Minute 4: passwords.txt

Took us 4 minutes to find the database password. It was in a file called passwords.txt in the public web directory.

Not buried in a config file. Not obscured behind a cryptic filename. passwords.txt. In the document root. Accessible to anyone with a browser. We typed the URL, the file downloaded, and there it was: the MySQL root password, the admin panel password, the SMTP password and the AWS access key. All in plaintext. All on separate lines, helpfully labeled.

This was not a hobbyist project. This was a production SaaS application processing payments for over 2,000 customers.

Minute 8: The Database Was Public

The MySQL password from the text file worked, obviously. But what made it worse was that the database server was accessible from the internet. No VPN required. No IP allowlist. Port 3306 was open to the world. Anyone with the credentials from that text file, which again was publicly downloadable, could connect directly to the production database from their laptop.

We connected. The database had 47 tables. Customer names, email addresses, physical addresses, phone numbers, payment history. The payments table referenced Stripe customer IDs, which meant the Stripe API key (also in passwords.txt) could pull full payment card details.

Minute 15: The Admin Panel Used "admin/admin"

We found the admin panel at /admin. The credentials were admin/admin. The default credentials that ship with the framework. Never changed. The admin panel gave full access to every user account, the ability to impersonate any user, export all data and modify application settings including the payment gateway configuration.

At this point we had been working for 15 minutes.

Minute 22: Backups in the Downloads Folder

Directory listing was enabled on the server. We browsed to /backups/ and found weekly database dumps going back 8 months. Each file was a complete mysqldump of the production database. Unencrypted. Uncompressed. Named with the date. Anyone could download the entire customer database, every version of it, for the past 8 months.

The backups also contained older versions of the passwords file with previous credentials. Some of those previous credentials still worked on other systems in the same infrastructure.

Minute 30: The Staging Server Was Worse

While reviewing the DNS records, we found a staging subdomain. staging.clientdomain.com. It ran an older version of the application with debug mode enabled. The debug panel exposed the full server configuration, all environment variables, every SQL query in real time and a built-in terminal emulator.

The terminal emulator ran as root. We had full shell access to the staging server through a web browser. The staging server was on the same network as production, with no segmentation. From staging, we could reach every production system.

Minute 40: Customer Data Was Being Logged

The application logged every request body to a file in /var/log/app/. Every login attempt, including the password field. Every payment form submission, including card numbers. Every profile update, including changes to personal information. The log files were never rotated. The oldest entry was 14 months old. Over 80,000 plaintext passwords and thousands of partial card numbers sitting in a log file.

This violated PCI-DSS, PIPEDA and basic common sense. The logging was configured by the developer for debugging and never turned off.

Minute 45: The Email Server Forwarded Everything

The SMTP credentials from the passwords file gave us access to the application's email account. We found an active forwarding rule sending a copy of every outgoing email to a personal Gmail address. Password reset links, invoice emails, welcome emails with temporary passwords. All forwarded. The forwarding rule had been active for 6 months.

We do not know who set it up. The client did not recognize the Gmail address.

What the Client Said

When we delivered the report, the founder said something we hear often: "We knew we should have done this sooner." The fix took three weeks. Moving credentials to environment variables, closing the database port, changing every password, enabling encryption on backups, disabling directory listing, removing the staging terminal, purging the logs, revoking the Stripe key and investigating the email forwarding rule.

The cost of the pentest was $4,500 CAD. The cost of not doing it would have been a mandatory PIPEDA breach notification to over 2,000 customers, potential regulatory fines and the complete destruction of customer trust.

Why This Keeps Happening

This engagement is a composite of real findings from multiple assessments, anonymized and combined. But every individual finding in this story has happened more than once. The passwords.txt pattern is more common than you would expect. The public database port is nearly universal among small teams. The default admin credentials appear in roughly one out of every three assessments we run.

These are not sophisticated attacks. We did not write custom exploits or chain zero-days. We typed URLs into a browser and tried default passwords. An automated scanner would have found most of these issues. A motivated teenager could have found all of them.

The question is not whether your application has these vulnerabilities. The question is whether you find them before someone else does.

Check Your Own Application

You can run a basic security check against your own site right now. It takes five minutes. Start with the obvious things: visit yourdomain.com/passwords.txt. Try /admin with default credentials. Check if directory listing is enabled. See if your .env file is downloadable.

If you find anything, do not panic. But do fix it today.