Thursday, April 4, 2013

The Evolution of Chrome Extensions Detection

Today's blog post is by guest blogger Giovanni Cattani.

The Old Technique

Detecting which Chrome extensions are installed has always been a trivial matter of finding a specific extension ID and trying to load the manifest.json file, which is always located in the same spot:


However, in the latest Chrome versions, attempting to load the manifest usually fails and the JavaScript console returns the following error:

Denying load of chrome-extension://abcdefghijklmnopqrstuvwxyz012345/manifest.json. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.

Load Error

What happened to the good old detection code that used to work seamlessly? And what is the web_accessible_resources manifest key?

Manifest Version 2

In Chrome 18, manifest version 1 was deprecated. Google is slowly decreasing its support, finally making it unavailable to developers in September 2013. In the new version, Google introduced several changes to the manifest file and one of them is breaking most of the existing detection code.

The web_accessible_resources array was introduced to allow developers to choose exactly which resources can be reached by external sources. If a local resource isn't included in the array, then a remote web page won't be able to load it. The array looks like the following example:

"web_accessible_resources": [ "logo.png", "menu.html", "style.css" ]

In order to determine the manifest version, the manifest.json file must be checked properly. The "manifest_version" parameter is self-explanatory and determines if the JSON has been updated to the latest version. If the manifest is already in the latest version ("manifest_version": 2), then the file includes the web_accessible_resources array.

Detecting Extensions

First of all, check the web_accessible_resources array and determine the resources that can be loaded. If the array is not empty, choose a resource of your choice, knowing that its location is chrome-extension://[EXTENSION ID]/[RESOURCE PATH].

Exactly like the old implementation, the simpler way to reliably detect whether an extension is installed or not with JavaScript is by creating a script element in the page and setting its source as one of the local extensions' resources. The following piece of code allows users to determine if a specific extension is installed by executing an arbitrary action when the local resource is loaded.

var testScript = document.createElement("script");           
testScript.setAttribute("onload", "alert('Extension Installed!')");
testScript.setAttribute("src", "chrome-extension://[EXTENSION ID]/[RESOURCE PATH]");

The previous code should work for every type of file, whether it's a text file (eg. json, html, script) or a picture.


The new implementation of the Chrome extension manifest provides developers with an easy way to whitelist resources loaded from external sources. Any code developed in order to detect installed add-ons won't be affected, as long as extensions keep allowing at least one local resource in the web_accessible_resources array.


Giovanni Cattani works as a security specialist and likes to mess around with applications of all kinds. He occasionally contributes to BeEF and writes about stuff he likes at


  1. Chrome performance with or without extensions has been really good and working with my documents as well as reading on the chromebook has been easy. Personally, I use a chrome extension for GroupDocs Viewer to view my files and read old PDF e-books. It has proved to be a handy extension for me and I get nice rendered files to view. You can also read an article for developing such extensions and I guess it will be a valued resource for developers as well as users.

    1. dongtam
      game mu
      nhạc sàn
      tư vấn luật
      dịch vụ thành lập công ty trọn gói
      công ty luật
      tổng đài tư vấn pháp luật
      thành lập công ty
      chém gió
      trung tâm ngoại ngữbốn cái quyển trục, ta trước tiên đem phòng ngự của bọn hắn xé nát, mọi người theo như nhu cầu như thế nào?

      Nghe vậy tất cả mọi người là khẽ gật đầu, biểu thị đồng ý Tiêu Viêm cách nhìn.

      Chợt, pound mỏng đấu khí theo Tiêu Viêm trong cơ thể phát ra mà ra. Nháy mắt sau đó, một cỗ quang mang màu vàng bao trùm tại bọn hắn trên nắm tay, đây chính là Tiêu Viêm thường xuyên dùng một chiêu thức, cũng là Tiêu Viêm lĩnh ngộ chiêu thức —— Viêm Đế quyền!

      Quyền khởi quyền rơi, chính giữa mang theo lôi đình vạn quân chi lực, hơn nữa tốc độ có thể nói là tương đương mau lẹ, cùng không khí sinh ra ông minh âm bạo thanh âm, nhưng là cái kia bốn cái quang đoàn, lại không có trong tưởng tượng vỡ tan thanh âm, chỉ là cái kia dấu quyền đi qua,

  2. "testScript.setAttribute("src", "chrome-extension://[EXTENSION ID]/[RESOURCE PATH]");"

    Here what to specify in [RESOURCE PATH]

    1. path to any file that is available in web_accessible_resources list.
      if "web_accessible_resources": [ "logo.png", "menu.html", "style.css" ]
      e.g., chrome-extension://[EXTENSION ID]/logo.png

  3. can we have a function returning true or false based on whether extension is installed or not. it would help if you provide code snippet for this.

  4. Here's what I came up with for a solution. Note the Chrome App I was after didn't have web_accessible_resources exposed.

    if (typeof chrome !== "undefined") {
    var ce = "chrome-extension://pnhechapfaindjhompbnflcldabbghjo/html/nassh.html";
    $.get(ce, function( data ) {
    .fail(function() {
    alert('Not found');

    1. This will always return not found unless the var ce IS a web_accessible_resources I tried it with all resources.


  5. Thanks for posting this useful content, Good to know about new things here, Let me share this, . Hadoop training in pune

  6. This tool lets Web developers evaluate the performance of a site and determine if an image needs to be cropped or an audio file needs to be compressed to make the page load faster.
    extract emails

  7. Thanks for post. That would be great if you also visited this page.