A vibecoded pricing bug let people subscribe for $0 for six days before anyone noticed
Had Claude Code refactor our checkout flow to add an annual billing option alongside monthly. It worked in every test I ran, annual customers got charged correctly, monthly customers got charged correctly, everything looked clean.
What I didn't catch was a specific combination, someone applying a discount code and then switching plans before completing checkout, that caused the final price to recalculate against the wrong base amount. Instead of erroring out or defaulting to full price, it just quietly landed on zero.
Nobody typed in a hack, nobody exploited anything on purpose, the flow itself just handed out free subscriptions to whoever happened to click things in that particular order.
Took six days to notice, and only because I was manually checking Stripe for an unrelated reason and saw a cluster of $0.00 charges I couldn't explain. Roughly 40 people had gotten a free year of the product by the time I found it.
Fixing the bug was fast. Deciding what to do about the 40 people who were already in, upgrade them to properly paying, quietly let them keep it, reach out and explain, was the actually hard part.
Ended up honoring it for existing users and just fixing it going forward, felt like the least damaging option even though it cost real money.
Has a vibecoded bug ever actually hit your revenue directly, not just broken something visibly, but quietly cost you money before you noticed? And when you found it, did you claw it back from affected users or eat the cost and move on?
Replies
Honoring the 40 people instead of clawing it back feels like the right call, doesn't turn their mistake-free click into a second bad experience. What stands out to me is the recalc landing on zero instead of erroring or overcharging, that's a pretty specific failure mode for a discount plus plan-switch combo. Curious what the fix ended up being: does the charge get recomputed server-side from the live cart at the moment of payment now, or was it more of a guard added around that one path?
@vollos
Yeah, honoring them felt like the only version of "fixing" this that didn't create a second problem out of the first one.
On the technical side, the actual fix was recomputing server-side from the live cart at the moment of payment, not just guarding that one path. The original bug was that the discount got applied once during plan selection, then the plan-switch logic pulled a cached price object instead of re-deriving it, so switching plans after a discount was applied meant the discount got carried over onto a base price that had already changed underneath it.
@terranicgerald Makes sense that the fix went right to the source, pulling a stale cached price object instead of re-deriving explains exactly why it stayed silent instead of throwing. Curious if the fix also covers catching this class of thing before it hits Stripe, like flagging or blocking anything that computes to zero, or is it purely that this one calc path is fixed now and a different edge case would still need someone to notice manually?
Yes, and billing is the worst version of it, because money bugs don't throw. A broken feature errors and you notice. A broken price just computes a valid number that happens to be wrong, and everything downstream accepts it. Zero is a valid float.
Tests couldn't catch it because the dangerous input wasn't a value, it was a combination, discount plus plan-switch mid-flow. You can't enumerate every order of operations, so more test cases don't help. What does is an invariant that doesn't care how you got there: a paid plan resolving below some floor is never valid, hard-stop and alert. The real bug isn't the wrong recalc, it's that $0 was allowed to be an answer at all.
On the 40, right call, and the cheapest one long term. It was your bug, not their exploit. One thing I'd add: those 40 are now your warmest possible leads for a fair paid offer. Did they convert at renewal or churn?
@jernej_jan_kocica "Zero is a valid float" is going to live in my head for a while, that's the whole bug in four words.
On the 40, mixed results honestly. About a third converted to paying at renewal, roughly the same as our normal free trial conversion rate, which if anything made me feel a little better about the whole thing since it suggests the product held up on its own merits once they'd actually used it for a year. A chunk churned right at renewal, presumably people who never intended to pay and just happened to benefit from the bug rather than seek it out. And a handful reached out asking to pay early once they realized what had happened, which I wasn't expecting at all.
@terranicgerald The ones who reached out to pay early are the real signal there. That's not trial conversion, that's people telling you the product was worth more than the accident handed them. I'd treat that handful as your best case studies. Glad the line stuck.
No revenue-loss story to match this since we're pre-revenue, but the same shape hit our deliverability instead of our billing: an AI-run outreach batch bounced 17 of 36 sends (47%) to real business inboxes, then the AI-authored "fix" just guessed a different address prefix at the same domains and bounced the same outlets again six hours later. Same root cause as yours: a silent failure mode nobody had put a hard-stop invariant around. "Zero is a valid float" has a sibling in our world: a guessed email address looks exactly like a verified one right up until it bounces. The actual fix wasn't "guess better," it was a hard rule: an address only goes in a To: field if it was read directly off the target's own page that same run, source URL logged next to it. Bounces are permanent deliverability damage, not a retryable error, so the fix had to be structural, not a retry with better judgment. Curious whether you ended up encoding your invariant as a literal blocking check in the payment path itself, or more of a monitoring alert after the fact?