Using the Weblinks API to Reach JavaScript UAFs in Adobe Reader

February 06, 2019 | Abdul-Aziz Hariri

JavaScript vulnerabilities in Adobe Acrobat/Reader are getting fewer and fewer. I credit this to the “boom” that happened back in 2015 and 2016. Back then, a lot of Adobe Acrobat research emerged ranging from JavaScript API bypasses to the classic memory corruption style  vulnerabilities (i.e. Use-After-Free, Type Confusions, Heap/Stack Overflows, etc.). In fact, in 2015, ZDI disclosed 97 vulnerabilities affecting Adobe Acrobat/Reader with almost 90% of the 97 vulnerabilities affecting the JavaScript API. 2016 had a slight increase totaling 110 vulnerabilities with almost the same percentage of JavaScript vulnerabilities.

Most of the vulnerabilities targeted non-privileged JavaScript APIs. For those who are not familiar with Adobe Acrobat/Reader’s JavaScript API, the first thing you should know is that the JavaScript engine is a fork of Mozilla’s SpiderMonkey. Second, Adobe has a similar privileges architecture as SpiderMonkey. There are two privilege contexts: Privileged and Non-Privileged.  This in turn splits the JavaScript APIs also into two: Privileged APIs and Non-Privileged.

That said, it’s worth noting that probably 90-95% of the corruption vulnerabilities affecting the JavaScript APIs over the past couple of years mainly targeted non-privileged APIs. That still leaves us with a huge sum of non-audited, non-fuzzed, non-touched privileged APIs. That’s perfectly understandable since auditing privileged APIs is more involved. It also requires a JavaScript Privileges API bypass vulnerability to trigger and weaponize them. In other words, it’s more expensive. Thus, most of the big numbers heard around public research on how someone found tens or hundreds of vulnerabilities in Acrobat/Reader are mostly (if not ALL) image parsing vulnerabilities. It’s smart, if you ask me, but if you think that makes you hardcore, then we’re waiting for you at Pwn2Own, with your favorite image parsing bug weaponized and all of your Adobe CVEs on the back of your T-shirt of course. ;)

Trolling aside, we do still get some JavaScript vulnerabilities every now and then. Slapping this.closeDoc into API’s for UAF’s does not work anymore as far as I can tell. Well, at least for non-privileged APIs. New JavaScript UAF’s have been a little bit more elegant though they still have the same logic. For example, ZDI-18-1393, ZDI-18-1391, and ZDI-18-1394.

While all of the 3 vulnerabilities are Use-After-Free vulnerabilities, the logic is interesting. First, all of those are vulnerabilities that affected WebLinks. Links in Adobe Acrobat in general are handled inside the WebLinks.api plugin. There’s a set of JavaScript APIs exposed to handle links. For example, this.addLink API (where this is the Doc object) accepts two arguments and is used to add a new link to the specified page with the specified coordinates.

Here’s a code example:

Another API that is quite useful as it forces the Link object to be freed *wink* is the this.removeLinks API. As the name implies, it removes all the links on the specified page within the specified coordinates.

Here’s its code example:

So how do these APIs relate to the bugs I mentioned? Simple: Create a Link with addLink, force the Link to be freed with removeLinks, and finally re-use it somehow. Well, it’s not that simple but the logic is right for all of these bugs. Here’s a breakdown of the PoCs…


The PoC defines an array. It then defines a getter for the first element. The getter’s callback function calls a function that calls this.removeLinks to force any Link objects at a given coordinate to be freed. A link is then added using this.addLink with the borderColor attribute set to the array defined earlier.


The PoC defines an object named “mode”. It then defines a custom toString function which calls a function that calls this.removeLinks to force any Link objects at a given coordinate to be freed. A link is then added using this.addLink with the highlightMode attribute set to the object defined earlier.


The PoC defines a variable named “width”. It then defines a custom valueOf function that calls this.removeLinks to force any Link objects at a given coordinate to be freed. A link is then added using this.addLink with the borderWidth attribute set to the variable defined earlier.


 Although a lot of the non-privileged API’s have been heavily audited, there still are different methods that can still yield good results. Don’t forget that there’s still a huge attack surface waiting to be audited underneath the privileged APIs. Regardless, some more ingredients are required to reach those APIs (API restrictions bypasses). Even that can be challenging to defeat with the recent restrictions mitigations that Adobe rolled into Acrobat/Reader.

That’s it for today folks. Until next time, you can find me on Twitter at @AbdHariri, and follow the team for the latest in exploit techniques and security patches.