💥 Database Incident Notice
The site is back online and fully functional. The database structure has been repaired. The individual historical votes/ratings that existed before this incident could not be recovered and are gone.
🔍 What Happened?
Earlier that day, our logs showed roughly 63,000 automated SQL injection attempts against the site. Our defenses held — the app uses parameterized database queries throughout, and a built-in scanner had been logging every attempt to an admin-only alerts page. Nothing was compromised by the attack itself.
To be thorough, we asked our engineering assistant to run a broader security review of the codebase, specifically to check for old, forgotten developer/debug scripts sitting in the live web root without any login requirement — a common and serious class of security mistake. That review found about a dozen leftover files that should never have been publicly reachable, including one-time database setup and recovery tools left over from earlier development work.
In the course of testing whether those files were reachable, one of them — recovery/rebuild_database.php — actually executed. It was designed to re-run the site's historical SQL schema files against the live database as an emergency recovery tool. It was not supposed to be accessible without authentication, and it should have required a login or been removed from the server entirely after its original use. It had neither protection.
Running it caused a cascade of statement failures partway through the process — it tried to drop and rebuild several core tables, hit conflicts with newer parts of the schema that didn't exist when the recovery script was originally written, and aborted partway through one of its files. The practical result: the ratings table (which stores every individual 1–10 vote cast on a photo) was dropped and never successfully recreated, along with the aggregated photo_stats view that depends on it. This caused the homepage and several other pages to start returning server errors shortly afterward.
💔 What Was Actually Lost
We treated this seriously and audited the full scope before writing this notice. Here's exactly what was affected:
- Lost — cannot be recovered: Every individual rating vote (the 1–10 scores users cast on photos) stored in the
ratingstable. The table itself has been rebuilt so voting works again, but the historical rows are gone. Aggregate stats like average rating and total vote counts on older photos will reset to zero and rebuild from new votes going forward. - Confirmed intact — verified directly after the incident: All photos (2,167 records), all user accounts (156 records) and login sessions (483 active sessions — nobody was logged out), all categories, all videos (61 records) and — importantly — all video ratings (70,706 records, a completely separate table that was not touched), and all site settings.
In short: photo rating history is gone. Everything else — accounts, photos, videos, video ratings, logins — was checked table-by-table and confirmed untouched.
⚙️ What We Did About It
- Immediate lockdown: The script that caused this, along with roughly a dozen other unauthenticated leftover dev/debug/recovery tools discovered during the same review, were deleted from the live server entirely.
- Schema repair: The
ratingstable andphoto_statsview were manually rebuilt to match what the application code actually expects, restoring normal site function. - Full impact audit: Every table plausibly affected was checked directly against the live database (not assumed) before reporting back — including tables that turned out to be completely unaffected, like video ratings.
- Process failure under review: A destructive, unauthenticated recovery script should never have been reachable in production in the first place, and a routine security check should never have been able to trigger a live schema change without an explicit, separate confirmation step. We are reviewing how these debug/recovery tools accumulated in the live web root over time and putting a stricter process in place to prevent it from happening again.
🙇 Apology
We're sorry. This should not have happened, full stop. A security review meant to make the site safer instead caused real, permanent data loss for our users and community — the second time this platform has lost data to an incident. That is an unacceptable outcome regardless of intent, and we're not going to dress it up as anything other than a serious mistake on our part.
If you rated photos before July 16, 2026, that specific vote history is gone. We know that matters to people who cared about their standings, leaderboard positions, or stats built up over time, and we're genuinely sorry for that loss.
📅 Timeline
- Earlier in the day: ~63,000 automated SQL injection attempts detected and logged; site defenses held, no compromise.
- During remediation review: An unauthenticated legacy recovery script was found to still be live and, in the course of checking it, executed against the production database.
- Shortly after: Homepage and several other pages began returning server errors due to the missing
ratingstable. - Same day: Root cause identified from server logs;
ratingstable andphoto_statsview rebuilt; site restored to normal function. - Same day: All other tables audited and confirmed intact; all leftover unauthenticated dev/recovery scripts removed from the live server.
- July 16, 2026 — This statement published.
Voting is back to normal — go ahead and re-rate the photos you'd rated before, we'd genuinely appreciate it. Thank you for bearing with us, and we're sorry for the loss.