Steam Vulnerabilities – Part 1


I decided to take a look at the security of Valve’s websites recently after noticing Valve put up a security disclosure page two weeks ago. Although I did take a look at non-Steam websites, I focused almost entirely on the Steam Community and store because of how widely it is used via the Steam client.

I submit these issues and most of them were fixed within a week. So if you know of any Steam or Valve related product exploits and haven’t had a chance or are not sure how to report them, you can send the vulnerabilities in an email to

Exploit #1: Force users to be your friend and bypass some of their privacy settings.


When you submit a friend request through Steam, you’re sending a web request called AddFriendAjax. In this request you are sending the person’s Steam ID and whether or not you are accepting an invite that was sent to you. It does this because this is the same request you send when you are accepting a friend invite.

My assumption on how this script works is that when you send a friend request you are both flagged as pending friends. When you send the request again but with accept_invite set to true, it checks if you are pending and sets you both as friends if you are.

The exploit here is that you were able to send the initial friend request and also accept the invite, forcing you to be their friend without them accepting or ignoring it. It did not work completely as you are still considered pending on their end.

AddFriendAjax Request

POST: sessionID=&steamid=&accept_invite=0

The sessionID is a mix between authentication and CSRF protection. The steamid is the person you are sending a friend request to or accepting a request from. accept_invite is a boolean that is asking whether you are sending a friend request or accepting one.

Here’s a screenshot walkthrough of the exploit:

No friends (the 1 is cached, I removed them from the list for this example)

A private user that I am about to send a friend request to:

Friend invite sent:

With just a friend invite, we’re not friends:

I sent another friend request but this time with accept_invite set to 1

Now we’re listed as friends, but I still don’t have complete access:

I’m still set as pending on that person’s friend list even though I’m their friend on my account:

I can still see information about their activity even though we aren’t truly friends:

Exploit #2: Modify the text, privacy, and reset any Steam game review by review Id.


Steam allows users to write reviews about games when they have purchased and played the game for more than 10 minutes.

These reviews are displayed on the game’s community hub and store page. The ratings are sorted by how helpful they are, which is based on Steam users voting whether the review was helpful by voting with a thumbs up or thumbs down. Some of these reviews have upwards of 12,000 ratings or more.

When you edit your review, you send the following request:

POST: review_text=&voted_up=true&sessionid=[sessionId]

This is also the same endpoint used when modifying the language and visibility of a review:

POST: is_public=false&sessionid=[sessionId]

There was no permission check on this request and you were able to plug in any review Id. This was especially a problem because when you edit a review’s text, the review loses all ratings and would be sent down to the bottom. As you can expect, this could have been abused to modify millions of game reviews on Steam.

Exploit #3: Stored Cross-Site Scripting and RSS/XML injection in Group Announcements


This exploit was interesting because all group announcements are put into the activity feed.

There are several locations on the Steam Community website where instead of encoded user input they retain CDATA encapsulation. Basically, if you put ]]> in your request, it’s going to put <![CDATA[ in immediately after it. This is the one location that I discovered where it failed to do this, allowing you to break out of CDATA and inject XML.

Here is what the group RSS feed looks like:

This allowed you to fabricate group announcements with fake data that could not normally be manipulated. More importantly, it allowed you to inject JavaScript into a location that the Steam client would execute.

Cross-Site Scripting in the Steam client is especially a problem because it could be used to force users to create trade proposals. This would essentially hand over their items to other Steam accounts without the victim even knowing about it until the item is gone.

What it looks like in the activity feed source:

In the browser:

In the Steam client:

The payload:

POST: sessionID=&action=post&headline=Test1]]></title></item><item><title>Test+XSS</title><description><script>alert(document.cookie)</script></description></item><item><title><![CDATA[Test3&body=Test

Exploit #4: Post announcements to any project on Project Greenlight.


Valve launched a new service called Steam Greenlight in 2012 that allowed companies to submit games, software, and concepts to a listing where the community can vote on them. When projects are Greenlit by Valve, developers are able to sell their game or software through the Steam platform.

One of the features of Steam Greenlight is being able to post announcements to all of the users following your project. The request for this feature looks like:

POST: id=[projectId]&sessionid=[sessionId]&postid=&action=&title=&description=

In this case, the projectId in the URI was being validated to make sure you had permission to post announcements to that project. However, the projectId in the POST id request variable was not being validated. As you can guess, the id in POST determined where the announcement would actually be posted.


  • Valve – for being awesome, recognizing the severity of the vulnerabilities and fixing the issues faster than expected.
  • Bill Eyler – for helping me test some of the Steam exploits and discovering a few vulnerabilities himself! Good work Bill 🙂