Leaky API for Best of Portland
Published on
in
🔒
Casting my vote
Around two months back, I received an email from my then employer letting us know that we were in the
Best of
Portland contest again with the local paper, the Willamette Week, and wanted us to vote for our company. For
those not in the know, the Best of Portland is an annual voting contest put on by the Willamette Week for
Portlanders to rank the best restaurants, bars, camps, child care, you name it.
Earlier in the week, I had attended a webinar put on by Black Hills Infosec (link to the talk) and an
interesting idea that was encouraged is just leaving the Dev Tools window in Chrome or Firefox open while
browsing around -- just to see what was out there, what error messages come up, etc. I took that advice and
just left the window open while doing my daily tasks and remembered that I should go cast my vote. Right then,
a UUID stuck out and just seemed different from the other calls being made.
Finding the API
bestofapi.scenethink.io seemed to be the API this data was coming from for this
particular category. So, like many of you would, I decided to just open it and see what
was there. I was not prepared to see every single vote cast in this category. Not only this
category but every single vote cast in the Best of Portland 2020 race! With also the persons'
full name, email address, and the personal IP address from that device…Uh oh.
Example of the URL:
https://bestofapi.scenethink.io/server/v1/ballots/xxxxxxxxxxx
Removing the ballot id at the end of the URL begat every voter on the platform,
not just the Willamette Week but also other news organizations that have used this platform
for "best of" votes and the test groups Scenethink's API showed.
Here's a list of them all:
- Best of Portland 2020
- Best of Portland 2020 Final Vote
- Best of Charleston 2020 Nominations
- Best of Charleston 2020 Final Vote
- Best of KC - 2020
- Best of KC 2020 Final Vote
- BOC Test (x2)
- BOC TEST 2
- Test Ballot (x2)
- Write In text 2
- SceneThink Demo Nominations
- New Nominations Ballot
Plugging the leak
Seeing how massive this leak was and that if anyone else went to that URL, they too could
view this information, I felt that I immediately had to reach out. But to who? Over 47 days
through
emails, I finally got confirmation that it was good to post about this.
After discovering the API's contents, starting here at https://bop.wweek.com/voter/index, a cookie
alert
linked me to a Privacy Policy. Devias' privacy policy took me to a contact form where I needed to agree to the
cookie terms before sending an email. I couldn't understand what the settings were telling me - it looks like
part of this is some "Lorem Ipsum" and wasn't actually saying anything. I sent an email through the contact
form to see if I could talk to someone and see if this was even something that they handled but never heard
back from them through this whole process.
I thought smaller, bestofapi.scenethink.io - could there be a Scenethink website? After some incredibly
easy
googling, I landed at Scenethink.com and started searching for their
privacy policy, thinking that whoever would be at privacy@scenethink.com would want to know this is happening
immediately. On their website, I found their intercom portal for
their knowledge base and saw a chat option. I sent a chat through their portal to see if I could talk with
someone about concerns
with their Best Of API and waited. And waited.
About a week later, one of the support staff from Scenethink got in touch with me and confirmed that
scenethink.io was their domain. I let them know all my findings - the email addresses, first and last names,
IP addresses, and a few hashed and salted passwords I had found in the output as well. A little while later I
received a 401 error if I went to the API's URL again.
So how could this have been fixed?
Some form of authentication or authorization needed to happen.
No one should just happen upon this data by accident, only people who need to see the information
should be
able to.This could have been acheived by starting a session and tying the user to that. That way, they would
only be able to see the things that they voted for.
Your API should not give extra information that is not required
If I had gone to https://bestofapi.scenethink.io/ballots, I should be required to provide a ballot ID
before
something is returned. I should not be able to see every single ballot that was ever made for this platform.
Providing extra information just gives someone a better idea about your platform -- if they don't need it,
don't provide it! This goes for really verbose error messages as well, unless it's someone at the company who
is working on the API, the average internet user does not need to know why something errored out.
Log large requests.
This goes hand in hand with the previous note - I shouldn't be able to view all of the records since
the API
started accepting requests. If someone requests a lot more data than expected, this should be logged somewhere
and require a follow-up from the security team.
Have some contact information somewhere on your site
It really shouldn't have taken almost two months to find who to contact and finally get this resolved.
Including some kind of contact information somewhere -- even if it's just a catch all email address -- is
better than nothing.
Finally, follow the OWASP top 10 guide on API Security
OWASP is far and away one of the trustworthy organizations when it comes to security -- their
recommendations are always spot on.
If you provide an API to the internet, make sure that your security is up to par - regardless of
whether you
think that no one will see it. I'm glad that I was able to share this finding and am looking forward to making
more posts in this vein!
Casting my vote
Around two months back, I received an email from my then employer letting us know that we were in the Best of Portland contest again with the local paper, the Willamette Week, and wanted us to vote for our company. For those not in the know, the Best of Portland is an annual voting contest put on by the Willamette Week for Portlanders to rank the best restaurants, bars, camps, child care, you name it.
Earlier in the week, I had attended a webinar put on by Black Hills Infosec (link to the talk) and an interesting idea that was encouraged is just leaving the Dev Tools window in Chrome or Firefox open while browsing around -- just to see what was out there, what error messages come up, etc. I took that advice and just left the window open while doing my daily tasks and remembered that I should go cast my vote. Right then, a UUID stuck out and just seemed different from the other calls being made.
Finding the API
bestofapi.scenethink.io seemed to be the API this data was coming from for this particular category. So, like many of you would, I decided to just open it and see what was there. I was not prepared to see every single vote cast in this category. Not only this category but every single vote cast in the Best of Portland 2020 race! With also the persons' full name, email address, and the personal IP address from that device…Uh oh.
Example of the URL:
https://bestofapi.scenethink.io/server/v1/ballots/xxxxxxxxxxx
Removing the ballot id at the end of the URL begat every voter on the platform, not just the Willamette Week but also other news organizations that have used this platform for "best of" votes and the test groups Scenethink's API showed.
Here's a list of them all:
- Best of Portland 2020
- Best of Portland 2020 Final Vote
- Best of Charleston 2020 Nominations
- Best of Charleston 2020 Final Vote
- Best of KC - 2020
- Best of KC 2020 Final Vote
- BOC Test (x2)
- BOC TEST 2
- Test Ballot (x2)
- Write In text 2
- SceneThink Demo Nominations
- New Nominations Ballot
Plugging the leak
Seeing how massive this leak was and that if anyone else went to that URL, they too could view this information, I felt that I immediately had to reach out. But to who? Over 47 days through emails, I finally got confirmation that it was good to post about this.
After discovering the API's contents, starting here at https://bop.wweek.com/voter/index, a cookie alert linked me to a Privacy Policy. Devias' privacy policy took me to a contact form where I needed to agree to the cookie terms before sending an email. I couldn't understand what the settings were telling me - it looks like part of this is some "Lorem Ipsum" and wasn't actually saying anything. I sent an email through the contact form to see if I could talk to someone and see if this was even something that they handled but never heard back from them through this whole process.
I thought smaller, bestofapi.scenethink.io - could there be a Scenethink website? After some incredibly easy googling, I landed at Scenethink.com and started searching for their privacy policy, thinking that whoever would be at privacy@scenethink.com would want to know this is happening immediately. On their website, I found their intercom portal for their knowledge base and saw a chat option. I sent a chat through their portal to see if I could talk with someone about concerns with their Best Of API and waited. And waited.
About a week later, one of the support staff from Scenethink got in touch with me and confirmed that scenethink.io was their domain. I let them know all my findings - the email addresses, first and last names, IP addresses, and a few hashed and salted passwords I had found in the output as well. A little while later I received a 401 error if I went to the API's URL again.
So how could this have been fixed?
Some form of authentication or authorization needed to happen.
No one should just happen upon this data by accident, only people who need to see the information should be able to.This could have been acheived by starting a session and tying the user to that. That way, they would only be able to see the things that they voted for.
Your API should not give extra information that is not required
If I had gone to https://bestofapi.scenethink.io/ballots, I should be required to provide a ballot ID before something is returned. I should not be able to see every single ballot that was ever made for this platform. Providing extra information just gives someone a better idea about your platform -- if they don't need it, don't provide it! This goes for really verbose error messages as well, unless it's someone at the company who is working on the API, the average internet user does not need to know why something errored out.
Log large requests.
This goes hand in hand with the previous note - I shouldn't be able to view all of the records since the API started accepting requests. If someone requests a lot more data than expected, this should be logged somewhere and require a follow-up from the security team.
Have some contact information somewhere on your site
It really shouldn't have taken almost two months to find who to contact and finally get this resolved. Including some kind of contact information somewhere -- even if it's just a catch all email address -- is better than nothing.
Finally, follow the OWASP top 10 guide on API Security
OWASP is far and away one of the trustworthy organizations when it comes to security -- their recommendations are always spot on.
If you provide an API to the internet, make sure that your security is up to par - regardless of whether you think that no one will see it. I'm glad that I was able to share this finding and am looking forward to making more posts in this vein!