← Back to Blog Posts

Someone Tried to Bankrupt My Cloud App

How a rogue user sent my Google Cloud bill into the stratosphere.

April 2, 2026

Header image for the blog post about a rogue user trying to bankrupt a cloud app.

There's a particular kind of Monday morning that every solo developer dreads. You open your email. There's a message from Google Cloud. The subject line contains a number that makes your coffee go cold.

That was my Monday.

🔍 The Discovery

I run a cloud-spotting app called Cloud Point — it lets people photograph the sky, identify cloud types using AI, and share their finds with a global community of people who enjoy looking up. It's a peaceful app. It's about clouds. Clouds are calm. Clouds don't cause drama.

Or so I thought.

I'd noticed my Firebase billing had climbed. Not a gentle drift upward like a cumulus on a summer afternoon — more like a cumulonimbus anvil shooting straight to the tropopause. Something was very wrong.

Google Cloud cost trend chart from March 2025 to March 2026 showing costs spiking dramatically in February and March, blowing past the £10 budget threshold.
The Google Cloud cost trend that ruined my Monday. Spot when TheBug08 arrived.

In fairness, the numbers weren't catastrophic yet — but the trajectory was. That bar wasn't climbing, it was launching. Another week of inaction and I'd have been looking at a bill that would make my eyes water. The only lucky part of this story is that I caught it while the rocket was still on the launchpad rather than in orbit.

So I did what any developer does when the bill spikes: I panicked briefly, then opened the Firebase console. And there, nestled among my perfectly normal cloud-spotting users, was a name that will live in infamy.

TheBug0502.

A username that, in hindsight, was basically a signed confession.

🐛 What TheBug0502 Was Up To

TheBug0502 had been busy. Incredibly busy. They had uploaded an extraordinary number of images to my app. We're talking volumes of content that would put an entire meteorological society to shame.

Scrolling through TheBug0502's uploads. It just keeps going.

But here's the bizarre part — none of the images were actually displaying. If you navigated to the Firebase Storage URLs, you'd get a permissions error. The images were ghosts. Phantom uploads. Digital vapour clogging up my storage bucket and bleeding my wallet dry.

A TheBug0502 post in Cloud Point showing no image — just the cloud type voting interface with zero hearts.
One of TheBug0502's phantom posts — no image, zero hearts, just wasted storage writes.

The bill was climbing because Firebase charges for storage writes, bandwidth, and Firestore operations. TheBug0502 wasn't trying to use my app. They were trying to exhaust it. Every upload cost me money regardless of whether the image ever rendered for another human being.

They'd somehow got themselves a premium subscription too, which meant the upload limits I'd set for free users weren't doing their job as a natural throttle. Cloud Point gives free users 5 MB of storage — premium unlocks unlimited identification and advanced features. TheBug0502 had apparently decided "unlimited" was a challenge, not a feature.

Whether the subscription was legitimate or spoofed was another question entirely — one I'd need to investigate.

Cloud Point All Time leaderboard showing TheBug0502 in first place with 2920 points, well ahead of everyone else.
TheBug0502 casually sitting at #1 on the All Time leaderboard. Not suspicious at all.

😱 The "Oh No" Moment

Here's the thing about Firebase: it's brilliant for getting an app off the ground quickly. It handles auth, storage, databases, and hosting with minimal backend code. But that convenience has a shadow side — if you haven't locked things down properly, a single motivated user can run up your bill like a teenager with a parent's credit card at an all-you-can-eat buffet.

My security rules were... fine. They were fine. They checked that users were authenticated before writing. They scoped uploads to user-specific paths. What they didn't do was rate-limit. They didn't cap how much a single user could upload per hour, per day, or per lifetime. They didn't have a concept of a banned user.

In other words, my front door had a lock, but once you were inside, you could rearrange all the furniture and I'd just have to watch.

🛠️ The Fix: Triage Mode

When your backend is actively haemorrhaging money, you don't have the luxury of an elegant solution. You need triage. Here's what I did, roughly in order:

Step 1: Disable the Account

Firebase Authentication lets you disable a user account without deleting it. This is important — you want the bleeding to stop, but you also want the evidence intact. Deleting the account would lose the UID, and I needed that to track down all their data.

I found TheBug0502's UID in the Firebase console and hit disable. Immediate effect: no more authenticated requests. The uploads stopped. The sky cleared, metaphorically speaking.

Step 2: Clean Up the Mess

TheBug0502 had left data scattered across Firestore collections and Storage buckets. Manually deleting each document and file would have taken hours, so I wrote a quick Node.js cleanup script using the Firebase Admin SDK.

The script queried every collection where a userId field matched their UID, batch-deleted the Firestore documents (in chunks of 500 — Firestore's batch limit), and then swept their Storage folder. One command, a few seconds of runtime, and the digital debris was gone.

Step 3: Verify the Subscription

Was the premium subscription real? This matters. If they paid through the App Store, it's a legitimate transaction even if the user is a menace. If they somehow bypassed receipt validation, that's a security hole. I checked my RevenueCat dashboard to confirm whether their subscription was genuine and whether it warranted any further action.

📚 The Bigger Lesson: What I Should Have Had in Place

TheBug0502 was a wake-up call. The kind of wake-up call that arrives in the form of an invoice. Here's what I've since implemented or plan to:

Rate Limiting via Security Rules

Firestore Security Rules can reference other documents. This means you can create a rate-limiting mechanism by maintaining a counter document for each user:

match /uploads/{userId}/{file} {
  allow write: if request.auth.uid == userId
                && getAfter(/databases/$(database)/documents/userCounts/$(userId)).data.dailyUploads < 50;
}

It's not perfect — there are race conditions at high concurrency — but for an indie app, it's a solid guardrail.

A Ban List

Rather than hardcoding blocked usernames into security rules (which is brittle and reactive), I now maintain a bannedUsers collection in Firestore. The security rules check for membership:

allow write: if !exists(/databases/$(database)/documents/bannedUsers/$(request.auth.uid));

Banning someone is now a single Firestore document write. No redeployment needed. Just swift, silent justice from above — like a cloud, but less fluffy.

Cloud Function Triggers

A storage.object().onFinalize() Cloud Function now runs on every upload. It checks file size, file type, upload frequency, and a few other heuristics. Anything suspicious gets flagged or auto-deleted before it accumulates cost.

Budget Alerts

Google Cloud lets you set budget alerts that notify you when spending hits certain thresholds. I had these set... but not aggressively enough. They're now configured to alert at much lower amounts so I catch anomalies within hours, not days.

📜 The Terms of Use I Didn't Have

Here's an embarrassing admission: before this incident, my app relied entirely on Apple's Standard EULA. That document protects Apple. It does not protect me.

It says nothing about what users can and can't do inside my app. It gives me no formal basis for banning someone, no clause about acceptable use, and no statement that abusive users aren't entitled to refunds.

I've since written proper Terms of Use that cover acceptable use, account termination at my discretion, and an explicit statement that subscriptions are non-refundable following a ban for abuse. If you're an indie developer reading this and you're still relying on Apple's standard EULA — go write your own terms. Today. Before your own TheBug0502 shows up.

You can literally see on the App Store listing that the Terms of Use link pointed straight to Apple's generic EULA. Rookie mistake. Don't be me.

❓ What I Still Don't Know

I don't know why TheBug0502 did this. Was it a bot? A bored teenager? A rival app developer who thought "cloud identifier" was a saturated market? Someone who was genuinely offended by my classification of their altocumulus as a stratocumulus?

The username suggests self-awareness — they knew they were being a pest. The images weren't displaying, which suggests either intentionally corrupted uploads or files that were being uploaded in a way that still triggered write costs without producing valid content. It's possible they were hitting the Firebase endpoints directly, bypassing the Flutter app entirely. If you know your way around the API, you don't need the UI.

Whatever the motivation, the result was the same: a spike in my cloud bill and a crash course in backend hardening that I should have taken before launch.

💡 Advice for Other Indie Developers

If you're building on Firebase (or any pay-per-use backend), here's my unsolicited advice, bought and paid for by TheBug0502's rampage:

Set budget alerts aggressively. Don't wait until the bill is alarming. Alert at the point where it's merely surprising.

Rate-limit everything. Every write, every upload, every API call. If a single user can generate unlimited operations, they will — whether by malice or by accident.

Have a ban mechanism ready. Not "I'll build one when I need it." Have it in your security rules from day one. A bannedUsers collection costs you nothing until you need it, and when you need it, you'll be glad it's there.

Write your own Terms of Use. Apple's standard EULA is not your friend. You need terms that give you the explicit right to moderate, suspend, and terminate.

Don't store what you can't afford. If your storage costs scale with user uploads, put hard limits on file sizes and counts. Make them generous enough for normal use and punishing enough that abuse is expensive for the abuser, not for you.

Disable first, delete later. When you find a problem account, disable it immediately to stop the damage. Keep the UID so you can audit and clean up properly.

⛅ The Silver Lining

Cloud Point is about looking up. It's about noticing the sky, identifying what you see, and sharing it with people who care about the same thing. It's a community app built on curiosity and calm.

TheBug0502 introduced turbulence. But if weather teaches you anything, it's that turbulence passes. The systems I've built since this incident are stronger than what came before. The app is more secure, the rules are tighter, and I now have a proper legal framework to fall back on.

So in a way, thanks, TheBug0502. You were an expensive lesson, but a valuable one.

Now please don't come back. The forecast is clear skies from here.


If you're curious about the app that survived the assault, you can check out Cloud Point on the App Store. It identifies clouds using AI, lets you share photos with a global community, and it now has much better security rules. You're welcome.

Got questions or war stories of your own? Drop me a line at hello@laurence-wayne.com.