New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 3 users

Issue metadata

Status: Fixed
Closed: Feb 9
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac , Fuchsia
Pri: 1
Type: Bug-Security

Sign in to add a comment

Cross-Origin image data leak via cache and canvas

Reported by, Jan 5 2018

Issue description

UserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3312.0 Safari/537.36

Steps to reproduce the problem:
1. Go to . This page has an img tag which loads a same-origin PNG image and an iframe tag which embeds a cross-origin page:

<img src="//" style="width:300px;height:100px;image-rendering:pixelated">
<iframe src="//"></iframe>

The `rgb.png` is an image having red, green and blue pixels.

The cross-origin page has the following code which loads the rgb.png on canvas:

<canvas id="canvas"></canvas>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = '//';
ctx.drawImage(img, 0, 0);

In additon, the page has the code which tries to read three pixels:


2.  See your console. Usually the `getImageData` method call against a cross-origin image is blocked. But if my PoC works well, you can see three pixel data:

Uint8ClampedArray(4) [255, 0, 0, 255] //red
Uint8ClampedArray(4) [0, 255, 0, 255] //green
Uint8ClampedArray(4) [0, 0, 255, 255] //blue

What is the expected behavior?
The following error should be thrown:
Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.

What went wrong?
The cross-origin data is leaked via cached data and cross-origin iframe.

Did this work before? N/A 

Chrome version: 65.0.3312.0  Channel: canary
OS Version: 10.0
Flash Version:
Components: Blink>Canvas
Status: Untriaged (was: Unconfirmed)
Very cool find.

I can reliably reproduce this in 63.0.3239.132 but not 64.0.3282.71 or 65.0.3312.0 (getting the Access Denied script error in both later builds), but it sounds like you're saying that you can reproduce this in Chrome 65?

Could you tweak the POC so that it shows the data in the frame instead of the console, so we can rule out any impact of the Developer Tools being open?
I modified the PoC. It shows the data in the frame now.
If you can't reproduce it, please use "Reload" button in the page instead of a manual reload. I can always reproduce it on 65.0.3312.0 via the button. 
RE #2: Thanks! 

I've reproduced this on Chrome 64.0.3282.71 on a Lenovo T460s, but I haven't yet managed to reproduce in Chrome 65. My guess is that there's a race condition somewhere in the loader/memory cache.

72.6 KB View Download
Labels: Security_Impact-Stable
Repros in ToT on the latest Chromium.
Version 65.0.3312.0 (Developer Build) (32-bit)

ImageResource::IsAccessAllowed is returning true from IsSameOriginOrCORSSuccessful().
In the insecure case, the IsSameOriginOrCORSSuccessful function returns true for the resource whose URL is "" because it has cors_status_ == CORSStatus::kSameOrigin.

In the secure case, IsSameOriginOrCORSSuccessful returns false and security_origin->TaintsCanvas(GetResponse().Url()) returns true, leading the canvas to be tainted.
Labels: Security_Severity-Medium OS-Linux
Status: Assigned (was: Untriaged)
I was also able to reproduce. 

I'll add that when I refresh the page the POC fails and I get the following warning in the console:

chrome_cache_image_leak.html:11 Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
    at Image.img.onload (

xlai@ could you take a look at this please?
Returning false from ImageResource::CanReuse makes the bug go away.

My non-expert guess about what happens is that we have two Resource Requests for the image running in parallel, one in the main frame and one in the subframe. If the request in the mainframe is registered first, the second request blocks on the completion of the first Resource and reuses it. Critically, however, the first Resource has a cors_status_ of CORSStatus::kSameOrigin as set by ResourceLoader::DetermineCORSStatus.

When the second context reuses the Resource, calls to ImageResource::IsAccessAllowed see that the Resource has a CORS status of kSameOrigin and does not care that |security_origin| has no relationship to |GetResponse().Url()|.

In contrast, if the timing works out such that the Resource isn't reused, the DetermineCORSStatus function gets called with a |source_origin| from the cross-origin subframe, and the Resource is NOT marked CORSStatus::kSameOrigin and the canvas is properly tainted. is the Chrome 61 CL that changed ImageResource::IsAccessAllowed to check the cached CORS status set by the ResourceLoader instead of performing an access-control check with the supplied |security_origin|.

Comment 9 by, Jan 5 2018

Components: -Blink>Canvas Blink>Image
Hmmm. I don't think this issue is in the implementation of canvas2d's GetImageData function. In this example, it reads the image from the ImageElement,
which is one type of CanvasImageSource. The cross-origin detection relies on the
value returns by WouldTaintOrigin(), which is overridden in ImageElementBase; by tracing the code, it is the ImageResourceContent::IsAccessAllowed that decides
the value.
I believe hintzed was an intern who has moved on. 

mkwst tends to be an expert in these sorts of things and may have a good suggestion on who should own.
Project Member

Comment 11 by, Jan 6 2018

Labels: M-64
Project Member

Comment 12 by, Jan 6 2018

Labels: -Pri-2 Pri-1
Project Member

Comment 13 by, Jan 20 2018

mkwst: Uh oh! This issue still open and hasn't been updated in the last 14 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit - Your friendly Sheriffbot

Comment 14 by, Jan 22 2018

Components: Blink>SecurityFeature>CORS
I believe toyoshim@ picked up the refactoring work hintzed@ started. toyoshim@, would you mind taking a look at this? CCing kinuko@ as well.
Status: Started (was: Assigned)
cc: relevant people, probably Something is wrong in DetermineRevalidationPolicy. Let me take a look.
hum... kForceCache was set against the resource for an unknown reason. Let me go deeper.
I'm seeing several related bugs on investigating the issue.

 1. Specifying kForceCache may bypass CORS check in DetermineRevalidationPolicy for image taint tracking.

 2. Memory cache is used for the second image load even DevTools disables the cache (not a security issue, but unexpected)

 3. kFrameLoadTypeBackForward is passed to the iframe for unknown reasons (now I'm investigating this)

3. will be the root cause of this specific bug, but 1. is also still a bad security issue if this is true even when JavaScript calls history.back

I will continue to investigate this tomorrow, but probably Hiroshige-san may have better knowledge on 1 and 2.
Oops, the reason of 3 is just because my Chrome restores the test page on launching. So, related problems are 1 and 2, and the root of this issue is DetermineRevalidationPolicy reaches to the last line that returns kUse.

Hiroshige-san, can you own this bug?
>1. is also still a bad security issue if this is true even when JavaScript calls history.back
I confirmed this bug works via history.back.
PoC is here:
Re #18, "2. Memory cache is used for the second image load even DevTools disables the cache (not a security issue, but unexpected)". 

I believe that is  Issue 644828 , which was deemed WONTFIX.

Labels: OS-Android OS-Chrome OS-Fuchsia OS-Mac
I talked with yhirano@.

So, current memory cache design shares the Resource instance over all origins in the same renderer process. But, CORSStatus was evaluated for the first request in ResourceLoader, and stored in the Resource instance. This is wrong, and we need to have the CORSStatus in ResourceClient side rather than Resource.

I think this is not a recent regression, but long living memory cache design issue. Let me check if we can have a fix without a large design change.

Note that this issue does not happen if site isolation is enabled (of course).
Plan A is to move the CORSStatus from Resource to ResourceClient. This is not s simple change.

Plan B is to stop sharing Resource instance among different source origins. Cons of this plan is we may see performance regressions for increased memory cache misses, but still it hits the disk cache. We will see a similar regression when we enable the site isolation. Also, once CORS support is moved out of renderer process, per-origin CORS check will require an IPC call to evaluate the CORSStatus for each origin.

So, at this point, Plan B looks reasonable even if we may see some performance regressions.
Had a VC with hiroshige.
I completely overlooked the comment #8, and will explore a CL that virtually reverts that change.
Hi Security Team, should the fix for this be merged to any release branch?

Information for the decision follows.

- This was regressed at m61
- Canvas image taint, and CORS and SRI checks for images and scripts can be bypassed, if it is still on memory cache
- The memory cache is shared among the same renderer process, that says if the site isolation is enabled, the issue should be hidden.

Tentatively reassigned to hiroshige@ who is trying to have the first fix.
Regarding merges: This is currently Severity-Medium, which makes a merge to Stable conditional upon the risk/complexity of the fix.
"If the fix seems too complicated to merge to the current stable milestone, assign it to the next stable milestone."

Having said that, can you please elaborate on 

"SRI checks for images and scripts can be bypassed, if it is still on memory cache"

How is the SRI check for scripts bypassed? That sounds significantly different than the issue with ImageResource::IsAccessAllowed. Is it? Has a bug with a repro for that issue been filed?
SRI should block (according to [1]) a subresource if CORS check fails OR the integrity check (e.g. hash check) fails.
Currently, e.g. no-cors cross-origin <script> with correct integrity attribute can be executed, while it should be (and had been) blocked due to lack of CORS headers. (I expect the security impact is smaller than the canvas taint check bypassing)

Correction to Comment #29:
In fact, the SRI issue is related to another issue that causes potential SRI bypassing, and probably this issue doesn't cause regression in SRI checks.
Wrote a patch that implements the approach I suggested in the VC.
Confirmed that this prevents pixels from being read by the script.
Project Member

Comment 32 by, Feb 7

The following revision refers to this bug:

commit fad67a5b73639d7211b24fd9bdb242e82039b765
Author: Hiroshige Hayashizaki <>
Date: Wed Feb 07 23:00:05 2018

Check CORS using PassesAccessControlCheck() with supplied SecurityOrigin

Partial revert of

Bug:  799477 
Change-Id: I878bb9bcb83afaafe8601293db9aa644fc5929b3
Commit-Queue: Hiroshige Hayashizaki <>
Reviewed-by: Kouhei Ueno <>
Reviewed-by: Yutaka Hirano <>
Reviewed-by: Takeshi Yoshino <>
Cr-Commit-Position: refs/heads/master@{#535176}

Labels: Merge-Request-65
The fix landed on 66.0.3343.0 and stayed on canary for one day. Requesting merge to M-65.
Project Member

Comment 34 by, Feb 9

Labels: -Merge-Request-65 Merge-Review-65 Hotlist-Merge-Review
This bug requires manual review: M65 has already been promoted to the beta branch, so this requires manual review
Please contact the milestone owner if you have questions.
Owners: cmasso@(Android), cmasso@(iOS), bhthompson@(ChromeOS), govind@(Desktop)

For more details visit - Your friendly Sheriffbot
+awhalley@ (Security TPM) for M65 merge review.
Project Member

Comment 36 by, Feb 9

Status: Fixed (was: Started)
Please mark security bugs as fixed as soon as the fix lands, and before requesting merges. This update is based on the merge- labels applied to this issue. Please reopen if this update was incorrect.

For more details visit - Your friendly Sheriffbot
Project Member

Comment 37 by, Feb 10

Labels: -Restrict-View-SecurityTeam Restrict-View-SecurityNotify
govind@ - good for 65
Labels: -Merge-Review-65 Merge-Approved-65
Approving merge to M65 branch 3325 based on comment #38. Please merge ASAP so we can pick it up for this week Beta release. Thank you.
Labels: reward-topanel
Project Member

Comment 41 by, Feb 12

Labels: -merge-approved-65 merge-merged-3325
The following revision refers to this bug:

commit 8f4341f9eb29137d8cc52bdd4d9fcdd2e1328b15
Author: Hiroshige Hayashizaki <>
Date: Mon Feb 12 21:52:23 2018

Check CORS using PassesAccessControlCheck() with supplied SecurityOrigin

Partial revert of

Bug:  799477 
Change-Id: I878bb9bcb83afaafe8601293db9aa644fc5929b3
Commit-Queue: Hiroshige Hayashizaki <>
Reviewed-by: Kouhei Ueno <>
Reviewed-by: Yutaka Hirano <>
Reviewed-by: Takeshi Yoshino <>
Cr-Original-Commit-Position: refs/heads/master@{#535176}(cherry picked from commit fad67a5b73639d7211b24fd9bdb242e82039b765)
Reviewed-by: Hiroshige Hayashizaki <>
Cr-Commit-Position: refs/branch-heads/3325@{#434}
Cr-Branched-From: bc084a8b5afa3744a74927344e304c02ae54189f-refs/heads/master@{#530369}

Checked the beta builder.


were all broken due to compile failure happened before hiroshige@'s patch.

They all passed later.

Project Member

Comment 43 by, Feb 19

The following revision refers to this bug:

commit c1df004861ab704945d31a0d207bb7f4c205e60c
Author: Takeshi Yoshino <>
Date: Mon Feb 19 05:25:55 2018

Stop reusing MemoryCache entries for requests with a different source origin.

ResourceFetcher/ResourceLoader now saves the result of the CORS check on
the Resource object. Though the result of the CORS check varies
depending on the source origin, reusing an existing resource fetched by
a different source origin is allowed by mistake.

This patch introduces a logic to prevent MemoryCache entries from being
reused for requests with a different source (requestor) origin by saving
the source origin on the Resource object and comparing that with the new
source origin in Resource::CanReuse(), so that the result of the CORS
check is reused only when the source origin is the same.

An alternative possibly-better approach is to isolate MemoryCache for
different origins by changing the cache identifier to take into account
the source origin of requests. However, to keep the patch small and fix
the issue quickly, this patch just prevents reuse.

Bug:  799477 , 809350
Change-Id: Ib96c9e728abe969a53f3d80519118a83392067b4
Commit-Queue: Takeshi Yoshino <>
Reviewed-by: Takashi Toyoshima <>
Reviewed-by: Yutaka Hirano <>
Cr-Commit-Position: refs/heads/master@{#537580}

Labels: -reward-topanel reward-unpaid reward-4000
*** Boilerplate reminders! ***
Please do NOT publicly disclose details until a fix has been released to all our users. Early public disclosure may cancel the provisional reward. Also, please be considerate about disclosure when the bug affects a core library that may be used by other products. Please do NOT share this information with third parties who are not directly involved in fixing the bug. Doing so may cancel the provisional reward. Please be honest if you have already disclosed anything publicly or to third parties. Lastly, we understand that some of you are not interested in money. We offer the option to donate your reward to an eligible charity. If you prefer this option, let us know and we will also match your donation - subject to our discretion. Any rewards that are unclaimed after 12 months will be donated to a charity of our choosing.
Congratulations masatokinugawa@! The VRP panel decided to award $4,000 for this report :-D
Labels: -reward-unpaid reward-inprocess
Labels: Release-0-M65
Labels: CVE-2018-6066
Project Member

Comment 49 by, Mar 27

Labels: -M-64 M-65
Labels: CVE_description-missing
Project Member

Comment 51 by, May 19

Labels: -Restrict-View-SecurityNotify allpublic
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit - Your friendly Sheriffbot

Sign in to add a comment