Closed Bug 1544310 Opened 5 years ago Closed 5 years ago

webRequest.filterResponseData allows extensions to bypass the Content Security Policy and execute remote code

Categories

(WebExtensions :: Request Handling, defect)

66 Branch
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED INVALID

People

(Reporter: robwu, Unassigned)

References

Details

Attachments

(1 file)

I was investigating the recent spike in reported crashes of bug 1403546, and came across several unlisted extensions. I analyzed a XPI that Andreas shared. The code is heavily obfuscated, but I managed to reverse engineer the logic and identify a security vulnerability in Firefox that allows unexpected remote code execution in the context of an extension page.

The vulnerability is the result of combining CSP relaxation with the webRequest.filterResponseData API.

The webRequest.filterResponseData API allows extensions to modify response bodies of requests.

The Content Security Policy is used to prevent extensions from executing remote code in privileged extension pages (e.g. background pages). The CSP defaults to the equivalent of script-src 'self'. Extensions can relax the policy via the content_security_policy field in manifest.json, and allow remote code via unsafe-eval or a https:-URL.

When unsafe-eval is used, it is quite clear that an extension may be executing remote code.
When a https:-URL is used, the expectation is that the extension may load a resource from that URL. If the URL is a well-known CDN, then a reviewer could mistakenly believe that the extension does not execute arbitrary code.

I will attach a test case in the next comment.

Attached file webRequest-rce.zip

STR:

  1. Load attached extension.

Expected:

  • No tab opens. The console of the background page (available via the "Debug" button at about:debugging) should show: SyntaxError: expected expression, got '<'

Actual:

  • A tab opens. This demonstrates that the extension was able to intercept the response to a https URL and replace it with arbitrary content. The content opens the test script itself in a new tab as a demonstration.

Cc-ing AMO admins for awareness.

This is expected

Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → INVALID

The behavior of the individual APIs are expected, but the consequences of the combination are not. Or at least, not desired.

When a well-known HTTPS URL is whitelisted, e.g. via

   "content_security_policy": "script-src https://ajax.googleapis.com/; object-src 'none';'

... then the expectation is that the extension only allows scripts from ajax.googleapis.com. Not that they can execute arbitrary scripts. In contrast, when 'unsafe-eval' is used, then it is obvious that an extension may run remote code.

I would expect the webRequest.filterResponseData to ignore script requests from extension origins to mitigate this issue.

There is already precedent for blocking undesired behavior, e.g. preventing the webRequest API from intercepting extension-initiated synchronous XHR.

It is both expected and desired.

Do you read past the first line of my comments? If you did, could you challenge the specific points that I make instead of giving few-word comments without context?

I claim that bypassing the content security policy via the webRequest API allows for unexpected remote code execution, which is a security risk.

There is no legitimate reason for allowing arbitrary strings to execute as privileged code. It makes auditing for malicious beheavior harder too. Without this vulnerability, privileged code execution is far more obvious:

  • The content_security_policy would include 'unsafe-eval', or
  • The content_security_policy would include an obscure https:-origin and the extension loads a https:-URL in a script tag, that clearly is not a standard library.
See Also: → 1544315

(Reopening pending more details)

Status: RESOLVED → REOPENED
Resolution: INVALID → ---

Kris has elaborated on his stance in IRC:

Because that's just the way stream filters work. If you have permission for a site, you can generate and change data as if you were that site. The same sort of behavior could be achieved by running a script on the site that let you send it data and then returned that data when you tried to load a script from it.

Basically, if your CSP allows running remote scripts, you're opting into running dynamically-generated scripts.

The CSP does explicitly allow it. It allows executing scripts from googleapis.com. The extension's host permissions allow it to speak for googleapis.com. Ergo, it explicitly allows it.

Though, strictly speaking, AMO shouldn't be accepting any add-ons with CSPs that allow remote scripts. That's been against policy for years.

This expectation makes sense when all remote resources are viewed as equally untrustworthy.
I previously assumed that there would be a difference between well-known hosts and obscure origins.
However, the AMO admins said that both are viewed as equally untrustworthy, so there is no point in putting effort into blocking modifications of script subresources in extension pages.

Status: REOPENED → RESOLVED
Closed: 5 years ago5 years ago
Resolution: --- → INVALID
Group: firefox-core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: