I have had many bad weeks but the one I'll be talking about here can't really be described better than with this screenshot from my Stripe dashboard:
What the hell happened?
In the span of one week in June 2021 my product, Thankbox, was targetted by fraudsters who managed to exploit the cash collection system using stolen cards. By the time I noticed this and stopped it they had drained close to $3000 in gift cards.
This is the story of how this happened and what I did to stop it. I was on the fence on whether or not I should write this, because I was afraid of making myself an even bigger target. I believe in learning from the mistakes of others though and this is what pushed me to do it.
This article will be intentionally vague on certain details in the interest of not exposing the protections I've put in place.
Background: how Thankbox collections work?
If you're new to my blog, I mostly write about my product Thankbox. It's a group card service with a cash collection feature. When a customer makes a card for someone they can open up a gift pot as well. Then their friends/colleagues can donate cash when they leave their message. The recipient of the card then claims that collected cash as a gift card using a service I've partnered with. Example of how that looks here.
It's a popular feature - it's been used to issue over $1,000,000 in gift cards so far. It's also fairly complex. I've built a lot of tracking and verification systems that work along the journey of the cash from collection to it finally being claimed by the recipient. A huge key to that is Stripe, my payment processor, and their wonderful API. I collect the cash using Stripe before sending it to my gift card provider.
Something looks wrong - discovering the fraud
On Sunday, June 20th 2021 I was out for a walk with my family and friends. It was Father's day, my daughter had just given me a card - I was happy and enjoying the sun. I opened my phone just to check the status of Thankbox sales for the day. Then I noticed that one person had bought about 10 Thankboxes, each with different gift pot sums. They were all getting sent to the same email address and had usage patterns that were unusual compared to a regular Thankbox. Then it hit me.
Oh. Shit.
I immediately understood what was going on and quickly blocked the user's account. I rushed home to get on my computer to investigate this more.
I went back through the week of collections and noticed similar situations had happened with different users. $50 here, $30 there, $200 in some other place. Since I couldn't be sure how many of these were in progress I just completely suspended the ability for recipients of a Thankbox to get their rewards until I could figure this out.
Just in time or too late? By that point I could see the total could be well over $2000. Within a few hours the Stripe dispute emails started coming in.
Stolen credit card fraud, duplicate card fraud, unauthorized use of card - pick a fraud reason and I would have seen it listed.
I spoke with my gift card provider and gave them the list of all the suspected fraudulent gift card claims. They said they'd try to cancel them but it's often not possible.
At that point I realised that not only would I be left with the loss of each of those transactions but I'd also end up getting a dispute fee of $15 for each one unless I refunded it before it was made. With a great deal of pain I opened up the Stripe dashboard, selected all of the suspected transactions I could be sure were fraudulent and refunded all of them.
Did you know that the gift card industry was worth $180 Billion in 2018? It's also ripe grounds for fraud because of how hard gift cards are to track once issued. I had just learned this the hard way.
An education in security - creating a fraud prevention system
I had bought myself some time with the issue pause I put in place but now I had to figure out how to move forward. I couldn't just keep a key feature of my product offline when 99% of it's usage is perfectly fine. I realized I needed a few key things:
- A system to detect potentially fraudulent collections.
- A way to approve or deny a flagged collection.
- A better way of preventing the transaction from even being accepted at the point it was made - via Stripe.
I first addressed point 1. I did some research and spoke with a couple of people I found with experience in credit card fraud to get advice. By talking with them about similar cases and analyzing patterns of what I had experienced I was able to quickly create a detection system which monitored and assigned a risk score to each collection. I made it in a way that I could modify, extend and adapt it easily since I was sure Thankbox would become a target again in the future.
For the first few days I set the risk threshold intentionally low - mostly because I was still quite paranoid. This resulted in a lot of false positives. So the next step was creating a process to approve or deny a flagged collection. Approving was the simple part. Denying was a bit more complex because it meant I had to do the following:
- Refund the Thankbox purchase.
- Refund all of the individual contributions that topped up that Thankbox.
- Send an email to the creator and recipient letting them know what happened.
Luckily I ended up adapting a system I had already put in place for handling regular refunds - like when a user deletes a message containing cash. The Stripe refund API is excellent help here. I also made sure to correctly set the refund reason as fraudulent
as that helps train Stripe's security system - more on that later. It also automatically adds the payment card to your account-specific block list so that all new payment attempts by it get rejected.
For the email I send I tried to strike a balance between a calm and kind but also strict tone. It both sends a message to actual fraudsters but is also sympathetic and leaves the door open in case it was an actual valid collection. This is the email that gets sent to the creator of the Thankbox:
Stop it at the source - the wonders of Stripe Radar
When I initially discovered what was happening I contacted Stripe to ask for advice on what to do. They suggested that I enable their fraud prevention system called Stripe Radar. It does cost extra at £0.02 per transaction but I decided that it's completely worth it. If I could stop a transaction from ever occuring it means there's no fraud consequences I have to directly deal with.
In a nutshell what Radar does is assign a risk level to each transaction. From 0 - completely safe, to 100 - highly risky.
You see the risk score of a transaction only if you have Radar enabled but even if you don't enable it, Stripe uses Radar for all transactions to provide a basic level of security. It automatically blocks attempted transactions above a certain risk score, for example. Thanks, Stripe - as if you needed another reason to be awesome in my book 🙌
With Radar enabled you have much more control of your security and can write as complex an approval/denial system as you like. You have a lot of attributes at your disposal - things like card country and number of attempted charges from a card or IP, for example.
The best part is that Radar uses Machine Learning to constantly improve. It's why Stripe encourage you to include their script on every page in your site (which I now do) and to correctly mark fraudulent transactions when you catch them - it all helps train Radar.
I'm still learning about how best to tune Radar to my particular use case but from what I see so far I think that, with a proper configuration, it can stop a large percentage of attempted fraud.
Turning the tide - stopping the second wave of attempts
The day my system went online I stopped two more attempts, then one more a day later. One of them I actually I had an early hunch about so I was quite pleased to see my code working in detecting it. In the list of failed Stripe transactions I saw my improved Radar rules stopping more attempts.
People say to try to separate yourself from your business but I will admit I took this personally. It scared me, then it made me angry. Angry that someone abused the product I've poured so much energy into this way. Thankfully, I used that anger productively - to focus on stopping the bleeding. Then putting the procedures in place to try to prevent it from happening again in the future.
And now I felt like I had some solid ground and was actually fighting back - and winning!
By the end of June the fraud attempts had died down. I don't know if it was because I managed to frustrate the scammers or if they had just decided to move on to their next victim. Regardless, I was just glad I could finally breathe a bit easier.
The aftermath of a hellish week
It's fair to say I did not have a fun Father's day or an enjoyable week afterwards. The final cost of the fraud, including all incurred dispute fees cost me nearly $3000. Not to mention the part of figuring out the bookkeeping around this - you'll be surprised at how complex the Thankbox accounting is and how much I had to untangle to get it done right after this.
I'm under no illusion that this is the last big issue I'll have with Thankbox. But this week really did make me believe that what doesn't kill you makes you stronger. It was yet another challenge to overcome, one more blindspot I now know about, which means there's one less ahead.
Thankbox continues to be the most successful product I ever built and I will defend it - aggresively.