Enforce CSP base-uri in HTML preload scanner [chromium/src : main]

0 views
Skip to first unread message

Andrew Paseltiner (Gerrit)

unread,
Apr 22, 2026, 8:07:49 AMApr 22
to Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, Yoav Weiss (@Shopify), blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
Attention needed from Kouhei Ueno

New activity on the change

Open in Gerrit

Related details

Attention is currently required from:
  • Kouhei Ueno
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
Gerrit-Change-Number: 7782696
Gerrit-PatchSet: 3
Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
Gerrit-CC: Yoav Weiss (@Shopify) <yoav...@chromium.org>
Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
Gerrit-Comment-Date: Wed, 22 Apr 2026 12:07:38 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Yoav Weiss (@Shopify) (Gerrit)

unread,
Apr 22, 2026, 10:00:10 AMApr 22
to Andrew Paseltiner, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
Attention needed from Andrew Paseltiner and Kouhei Ueno

Yoav Weiss (@Shopify) added 1 comment

Patchset-level comments
File-level comment, Patchset 3 (Latest):
Yoav Weiss (@Shopify) . resolved

What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

Open in Gerrit

Related details

Attention is currently required from:
  • Andrew Paseltiner
  • Kouhei Ueno
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
Gerrit-Change-Number: 7782696
Gerrit-PatchSet: 3
Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
Gerrit-CC: Yoav Weiss (@Shopify) <yoav...@chromium.org>
Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
Gerrit-Comment-Date: Wed, 22 Apr 2026 13:59:24 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Andrew Paseltiner (Gerrit)

unread,
Apr 22, 2026, 10:07:57 AMApr 22
to Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, Yoav Weiss (@Shopify), blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
Attention needed from Kouhei Ueno and Yoav Weiss (@Shopify)

Andrew Paseltiner added 1 comment

Patchset-level comments
Yoav Weiss (@Shopify) . unresolved

What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

Andrew Paseltiner

IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

Open in Gerrit

Related details

Attention is currently required from:
  • Kouhei Ueno
  • Yoav Weiss (@Shopify)
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-CC: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:07:50 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Yoav Weiss (@Shopify) (Gerrit)

    unread,
    Apr 22, 2026, 10:23:50 AMApr 22
    to Andrew Paseltiner, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Andrew Paseltiner and Kouhei Ueno

    Yoav Weiss (@Shopify) added 1 comment

    Patchset-level comments
    Yoav Weiss (@Shopify) . unresolved

    What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

    Andrew Paseltiner

    IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

    Yoav Weiss (@Shopify)

    Thanks for pushing back!

    You're right that the preload request path does end up with (header-based) CSP checks (and I believe CSP <meta> disables preloading, to avoid unauthorized requests in that case). The threat model behind the latter is unclear to me tbh, but that's a topic for a different conversation.

    Just to see that I understand why base-uri needs special casing here - we can't enforce base-uri restrictions at part of requestResource as we don't know there is the resource was fetched using a relative URL that relied on base URI?

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Andrew Paseltiner
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-CC: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:23:26 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Andrew Paseltiner <apase...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Andrew Paseltiner (Gerrit)

    unread,
    Apr 22, 2026, 10:27:02 AMApr 22
    to Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, Yoav Weiss (@Shopify), blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Kouhei Ueno and Yoav Weiss (@Shopify)

    Andrew Paseltiner added 1 comment

    Patchset-level comments
    Yoav Weiss (@Shopify) . unresolved

    What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

    Andrew Paseltiner

    IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

    Yoav Weiss (@Shopify)

    Thanks for pushing back!

    You're right that the preload request path does end up with (header-based) CSP checks (and I believe CSP <meta> disables preloading, to avoid unauthorized requests in that case). The threat model behind the latter is unclear to me tbh, but that's a topic for a different conversation.

    Just to see that I understand why base-uri needs special casing here - we can't enforce base-uri restrictions at part of requestResource as we don't know there is the resource was fetched using a relative URL that relied on base URI?

    Andrew Paseltiner

    Correct. Consider this document being preloaded:

    ```html
    <base href="https://foo.example">
    <img src="/bar">
    ```

    Without this CL, `/bar` is eagerly resolved to `https://foo.example/bar` and then fetched, meaning we've lost knowledge of whether there was a base URL at all by the time CSP comes into play. The alternative (Option 2 from the commit description) would be to avoid eager resolution at all (which I actually prefer from a code deduplication perspective) and instead let the fetch itself handle that, but IIUC it complicates the preload scanner's logic. If the reviewers push back though, we could consider it.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Kouhei Ueno
    • Yoav Weiss (@Shopify)
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-CC: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:26:57 +0000
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Yoav Weiss (@Shopify) (Gerrit)

    unread,
    Apr 22, 2026, 10:45:34 AMApr 22
    to Andrew Paseltiner, Antonio Sartori, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Andrew Paseltiner, Antonio Sartori and Kouhei Ueno

    Yoav Weiss (@Shopify) added 1 comment

    Patchset-level comments
    Yoav Weiss (@Shopify) . unresolved

    What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

    Andrew Paseltiner

    IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

    Yoav Weiss (@Shopify)

    Thanks for pushing back!

    You're right that the preload request path does end up with (header-based) CSP checks (and I believe CSP <meta> disables preloading, to avoid unauthorized requests in that case). The threat model behind the latter is unclear to me tbh, but that's a topic for a different conversation.

    Just to see that I understand why base-uri needs special casing here - we can't enforce base-uri restrictions at part of requestResource as we don't know there is the resource was fetched using a relative URL that relied on base URI?

    Andrew Paseltiner

    Correct. Consider this document being preloaded:

    ```html
    <base href="https://foo.example">
    <img src="/bar">
    ```

    Without this CL, `/bar` is eagerly resolved to `https://foo.example/bar` and then fetched, meaning we've lost knowledge of whether there was a base URL at all by the time CSP comes into play. The alternative (Option 2 from the commit description) would be to avoid eager resolution at all (which I actually prefer from a code deduplication perspective) and instead let the fetch itself handle that, but IIUC it complicates the preload scanner's logic. If the reviewers push back though, we could consider it.

    Yoav Weiss (@Shopify)

    I'm not opposed to copying in the CSP directives, as it can enable genuine support for <meta> CSP in the future (given that apparently we think it's important).

    Thinking through this, while I'm not sure there's a security risk, the spec does seem to require these requests are not sent to servers. Given that this is web-exposed, should we also add a WPT here?

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Andrew Paseltiner
    • Antonio Sartori
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Attention: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:45:19 +0000
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Andrew Paseltiner (Gerrit)

    unread,
    Apr 22, 2026, 10:50:00 AMApr 22
    to Antonio Sartori, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Antonio Sartori, Kouhei Ueno and Yoav Weiss (@Shopify)

    Andrew Paseltiner added 1 comment

    Patchset-level comments
    Yoav Weiss (@Shopify) . unresolved

    What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

    Andrew Paseltiner

    IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

    Yoav Weiss (@Shopify)

    Thanks for pushing back!

    You're right that the preload request path does end up with (header-based) CSP checks (and I believe CSP <meta> disables preloading, to avoid unauthorized requests in that case). The threat model behind the latter is unclear to me tbh, but that's a topic for a different conversation.

    Just to see that I understand why base-uri needs special casing here - we can't enforce base-uri restrictions at part of requestResource as we don't know there is the resource was fetched using a relative URL that relied on base URI?

    Andrew Paseltiner

    Correct. Consider this document being preloaded:

    ```html
    <base href="https://foo.example">
    <img src="/bar">
    ```

    Without this CL, `/bar` is eagerly resolved to `https://foo.example/bar` and then fetched, meaning we've lost knowledge of whether there was a base URL at all by the time CSP comes into play. The alternative (Option 2 from the commit description) would be to avoid eager resolution at all (which I actually prefer from a code deduplication perspective) and instead let the fetch itself handle that, but IIUC it complicates the preload scanner's logic. If the reviewers push back though, we could consider it.

    Yoav Weiss (@Shopify)

    I'm not opposed to copying in the CSP directives, as it can enable genuine support for <meta> CSP in the future (given that apparently we think it's important).

    Thinking through this, while I'm not sure there's a security risk, the spec does seem to require these requests are not sent to servers. Given that this is web-exposed, should we also add a WPT here?

    Andrew Paseltiner

    I was wondering about WPT myself, but I'm not sure how preloading works with it exactly. Any suggestions?

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Antonio Sartori
    • Kouhei Ueno
    • Yoav Weiss (@Shopify)
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:49:53 +0000
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Yoav Weiss (@Shopify) (Gerrit)

    unread,
    Apr 22, 2026, 10:51:38 AMApr 22
    to Andrew Paseltiner, Antonio Sartori, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Antonio Sartori, Kouhei Ueno and Yoav Weiss (@Shopify)

    Yoav Weiss (@Shopify) added 1 comment

    File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
    Line 1163, Patchset 3 (Latest): is_valid_base_url = false;
    Yoav Weiss (@Shopify) . unresolved

    IIUC, this won't skip preloading, but will preload resources while assuming that a base URL is not defined. That doesn't seem like the correct behavior

    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:51:11 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Andrew Paseltiner (Gerrit)

    unread,
    Apr 22, 2026, 10:56:19 AMApr 22
    to Antonio Sartori, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Antonio Sartori, Kouhei Ueno and Yoav Weiss (@Shopify)

    Andrew Paseltiner added 1 comment

    File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
    Line 1163, Patchset 3 (Latest): is_valid_base_url = false;
    Yoav Weiss (@Shopify) . unresolved

    IIUC, this won't skip preloading, but will preload resources while assuming that a base URL is not defined. That doesn't seem like the correct behavior

    Andrew Paseltiner
    Gerrit-Comment-Date: Wed, 22 Apr 2026 14:56:14 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Yoav Weiss (@Shopify) (Gerrit)

    unread,
    Apr 22, 2026, 4:57:10 PMApr 22
    to Andrew Paseltiner, Antonio Sartori, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Andrew Paseltiner, Antonio Sartori and Kouhei Ueno

    Yoav Weiss (@Shopify) added 2 comments

    Patchset-level comments
    Yoav Weiss (@Shopify) . unresolved

    What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

    Andrew Paseltiner

    IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

    Yoav Weiss (@Shopify)

    Thanks for pushing back!

    You're right that the preload request path does end up with (header-based) CSP checks (and I believe CSP <meta> disables preloading, to avoid unauthorized requests in that case). The threat model behind the latter is unclear to me tbh, but that's a topic for a different conversation.

    Just to see that I understand why base-uri needs special casing here - we can't enforce base-uri restrictions at part of requestResource as we don't know there is the resource was fetched using a relative URL that relied on base URI?

    Andrew Paseltiner

    Correct. Consider this document being preloaded:

    ```html
    <base href="https://foo.example">
    <img src="/bar">
    ```

    Without this CL, `/bar` is eagerly resolved to `https://foo.example/bar` and then fetched, meaning we've lost knowledge of whether there was a base URL at all by the time CSP comes into play. The alternative (Option 2 from the commit description) would be to avoid eager resolution at all (which I actually prefer from a code deduplication perspective) and instead let the fetch itself handle that, but IIUC it complicates the preload scanner's logic. If the reviewers push back though, we could consider it.

    Yoav Weiss (@Shopify)

    I'm not opposed to copying in the CSP directives, as it can enable genuine support for <meta> CSP in the future (given that apparently we think it's important).

    Thinking through this, while I'm not sure there's a security risk, the spec does seem to require these requests are not sent to servers. Given that this is web-exposed, should we also add a WPT here?

    Andrew Paseltiner

    I was wondering about WPT myself, but I'm not sure how preloading works with it exactly. Any suggestions?

    Yoav Weiss (@Shopify)

    What you can do is add a WPT with a blocking script that document.write()s an HTML comment, and then have HTML that loads resources after that. Those resources would get preloaded, but never actually loaded.

    Then you can use resource timing to see what loads were triggers and assert that the behavior matches what you'd expect.

    I guess you could also just verify that resources from an unallowed base-uri origin are never loaded (again using resource timing)

    File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
    Line 1163, Patchset 3 (Latest): is_valid_base_url = false;
    Yoav Weiss (@Shopify) . resolved

    IIUC, this won't skip preloading, but will preload resources while assuming that a base URL is not defined. That doesn't seem like the correct behavior

    Andrew Paseltiner

    IIUC that actually is the correct behavior: https://html.spec.whatwg.org/multipage/semantics.html#set-the-frozen-base-url.

    Yoav Weiss (@Shopify)

    Huh! That's.. an interesting choice. I guess that makes sense for XSS script dynamically trying to change the page's base.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Andrew Paseltiner
    • Antonio Sartori
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Attention: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Wed, 22 Apr 2026 20:56:56 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Andrew Paseltiner <apase...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Antonio Sartori (Gerrit)

    unread,
    Apr 23, 2026, 7:13:17 AMApr 23
    to Andrew Paseltiner, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Andrew Paseltiner and Kouhei Ueno

    Antonio Sartori added 1 comment

    File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
    Line 1159, Patchset 3 (Latest): if (!CSPDirectiveListAllowFromSource(
    *policy, nullptr, CSPDirectiveName::BaseURI, document_url_, url,
    url, ResourceRequest::RedirectStatus::kNoRedirect,
    ReportingDisposition::kSuppressReporting)) {
    Antonio Sartori . unresolved

    I am a slightly unhappy with calling CSPDirectiveListAllowFromSource directly. The design idea of the CSP checks was that you would only call methods from content_security_policy.h using a `ContentSecurityPolicy` object.

    Maybe it would make sense to add into content_security_policy.h a static method for checking base-uri without reporting. In this way we can add unit tests there and it's easier to make sure that everything keeps working even with a null ContentSecurityPolicy.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Andrew Paseltiner
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 3
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Thu, 23 Apr 2026 11:13:00 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Andrew Paseltiner (Gerrit)

    unread,
    Apr 23, 2026, 9:01:17 AMApr 23
    to Antonio Sartori, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Antonio Sartori and Kouhei Ueno

    Andrew Paseltiner voted and added 1 comment

    Votes added by Andrew Paseltiner

    Commit-Queue+1

    1 comment

    File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
    Line 1159, Patchset 3: if (!CSPDirectiveListAllowFromSource(

    *policy, nullptr, CSPDirectiveName::BaseURI, document_url_, url,
    url, ResourceRequest::RedirectStatus::kNoRedirect,
    ReportingDisposition::kSuppressReporting)) {
    Antonio Sartori . resolved

    I am a slightly unhappy with calling CSPDirectiveListAllowFromSource directly. The design idea of the CSP checks was that you would only call methods from content_security_policy.h using a `ContentSecurityPolicy` object.

    Maybe it would make sense to add into content_security_policy.h a static method for checking base-uri without reporting. In this way we can add unit tests there and it's easier to make sure that everything keeps working even with a null ContentSecurityPolicy.

    Andrew Paseltiner

    Done

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Antonio Sartori
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 4
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Thu, 23 Apr 2026 13:01:08 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Comment-In-Reply-To: Antonio Sartori <antonio...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Antonio Sartori (Gerrit)

    unread,
    Apr 23, 2026, 9:06:47 AMApr 23
    to Andrew Paseltiner, android-bu...@system.gserviceaccount.com, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Andrew Paseltiner and Kouhei Ueno

    Antonio Sartori added 1 comment

    File third_party/blink/renderer/core/frame/csp/content_security_policy.cc
    Line 1048, Patchset 4 (Latest): const KURL& document_url) {
    Antonio Sartori . unresolved

    I think `document_url` does nothing, and you should be able to remove this parameter and pass an empty url below.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Andrew Paseltiner
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 4
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Thu, 23 Apr 2026 13:06:31 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Andrew Paseltiner (Gerrit)

    unread,
    Apr 23, 2026, 9:16:33 AMApr 23
    to android-bu...@system.gserviceaccount.com, Antonio Sartori, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Antonio Sartori and Kouhei Ueno

    Andrew Paseltiner voted and added 1 comment

    Votes added by Andrew Paseltiner

    Commit-Queue+1

    1 comment

    File third_party/blink/renderer/core/frame/csp/content_security_policy.cc
    Line 1048, Patchset 4: const KURL& document_url) {
    Antonio Sartori . resolved

    I think `document_url` does nothing, and you should be able to remove this parameter and pass an empty url below.

    Andrew Paseltiner

    Done

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Antonio Sartori
    • Kouhei Ueno
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
    Gerrit-Change-Number: 7782696
    Gerrit-PatchSet: 5
    Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
    Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
    Gerrit-Attention: Antonio Sartori <antonio...@chromium.org>
    Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
    Gerrit-Comment-Date: Thu, 23 Apr 2026 13:16:29 +0000
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Antonio Sartori (Gerrit)

    unread,
    Apr 23, 2026, 11:28:28 AMApr 23
    to Andrew Paseltiner, android-bu...@system.gserviceaccount.com, Yoav Weiss (@Shopify), Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
    Attention needed from Andrew Paseltiner and Kouhei Ueno

    Antonio Sartori voted and added 1 comment

    Votes added by Antonio Sartori

    Code-Review+1

    1 comment

    Patchset-level comments
    File-level comment, Patchset 5 (Latest):
    Antonio Sartori . resolved

    Thanks! The CSP logic makes sense to me, it's a bit unfortunate that it is a bit hacky because of the cross-thread issue but I don't see much better options.

    I'll defer to the other owners for the PreloadScanner, of which I have only limited understanding.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Andrew Paseltiner
    • Kouhei Ueno
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement is not satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
      Gerrit-Change-Number: 7782696
      Gerrit-PatchSet: 5
      Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
      Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
      Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
      Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
      Gerrit-Comment-Date: Thu, 23 Apr 2026 15:28:11 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Yoav Weiss (@Shopify) (Gerrit)

      unread,
      Apr 23, 2026, 12:59:42 PMApr 23
      to Andrew Paseltiner, Antonio Sartori, android-bu...@system.gserviceaccount.com, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
      Attention needed from Andrew Paseltiner and Kouhei Ueno

      Yoav Weiss (@Shopify) voted and added 2 comments

      Votes added by Yoav Weiss (@Shopify)

      Code-Review+1

      2 comments

      Patchset-level comments
      Yoav Weiss (@Shopify) . resolved

      LGTM % nit

      I really think we want WPTs here, but maybe we can add them in a followup.

      File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
      Line 1337, Patchset 5 (Latest): document->GetExecutionContext()->GetContentSecurityPolicy()) {
      Yoav Weiss (@Shopify) . unresolved
      Maybe 
      ```
      if (ExecutionContext* context = document->GetExecutionContext()) {
      if (ContentSecurityPolicy* csp = context->GetContentSecurityPolicy()) {
      ...
      }
      }
      ```
      Open in Gerrit

      Related details

      Attention is currently required from:
      • Andrew Paseltiner
      • Kouhei Ueno
      Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
      Gerrit-Change-Number: 7782696
      Gerrit-PatchSet: 5
      Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
      Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
      Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
      Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
      Gerrit-Comment-Date: Thu, 23 Apr 2026 16:59:25 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Andrew Paseltiner (Gerrit)

      unread,
      8:38 AM (7 hours ago) 8:38 AM
      to Code Review Nudger, Yoav Weiss (@Shopify), Antonio Sartori, android-bu...@system.gserviceaccount.com, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
      Attention needed from Kouhei Ueno

      Andrew Paseltiner voted and added 1 comment

      Votes added by Andrew Paseltiner

      Commit-Queue+2

      1 comment

      File third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
      Line 1337, Patchset 5 (Latest): document->GetExecutionContext()->GetContentSecurityPolicy()) {
      Yoav Weiss (@Shopify) . resolved
      Maybe 
      ```
      if (ExecutionContext* context = document->GetExecutionContext()) {
      if (ContentSecurityPolicy* csp = context->GetContentSecurityPolicy()) {
      ...
      }
      }
      ```
      Andrew Paseltiner

      Acknowledged

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Kouhei Ueno
      Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
      Gerrit-Change-Number: 7782696
      Gerrit-PatchSet: 5
      Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
      Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
      Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
      Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
      Gerrit-CC: Code Review Nudger <android-build...@prod.google.com>
      Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
      Gerrit-Comment-Date: Mon, 01 Jun 2026 12:38:47 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Andrew Paseltiner (Gerrit)

      unread,
      8:39 AM (7 hours ago) 8:39 AM
      to Code Review Nudger, Yoav Weiss (@Shopify), Antonio Sartori, android-bu...@system.gserviceaccount.com, Kouhei Ueno, Chromium LUCI CQ, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org
      Attention needed from Andrew Paseltiner and Kouhei Ueno

      Andrew Paseltiner voted and added 1 comment

      Votes added by Andrew Paseltiner

      Commit-Queue+2

      1 comment

      Patchset-level comments
      Yoav Weiss (@Shopify) . resolved

      What's the threat model here? We don't currently enforce CSP for any of the other directives, and CSP's official threat model doesn't exclude exfiltration (and even if it did, that seems hard to pull off from static HTML that the preload scanner handles).

      Andrew Paseltiner

      IIUC, we actually do enforce CSP for the other directives, as they go through `BaseFetchContext::CheckCSPForRequest`. It's just that in this case, the URLs are eagerly resolved against the document's base URL, instead of being resolved at the time the request is actually being made, meaning that the base-uri directive is never being considered. The linked bug has more details.

      Yoav Weiss (@Shopify)

      Thanks for pushing back!

      You're right that the preload request path does end up with (header-based) CSP checks (and I believe CSP <meta> disables preloading, to avoid unauthorized requests in that case). The threat model behind the latter is unclear to me tbh, but that's a topic for a different conversation.

      Just to see that I understand why base-uri needs special casing here - we can't enforce base-uri restrictions at part of requestResource as we don't know there is the resource was fetched using a relative URL that relied on base URI?

      Andrew Paseltiner

      Correct. Consider this document being preloaded:

      ```html
      <base href="https://foo.example">
      <img src="/bar">
      ```

      Without this CL, `/bar` is eagerly resolved to `https://foo.example/bar` and then fetched, meaning we've lost knowledge of whether there was a base URL at all by the time CSP comes into play. The alternative (Option 2 from the commit description) would be to avoid eager resolution at all (which I actually prefer from a code deduplication perspective) and instead let the fetch itself handle that, but IIUC it complicates the preload scanner's logic. If the reviewers push back though, we could consider it.

      Yoav Weiss (@Shopify)

      I'm not opposed to copying in the CSP directives, as it can enable genuine support for <meta> CSP in the future (given that apparently we think it's important).

      Thinking through this, while I'm not sure there's a security risk, the spec does seem to require these requests are not sent to servers. Given that this is web-exposed, should we also add a WPT here?

      Andrew Paseltiner

      I was wondering about WPT myself, but I'm not sure how preloading works with it exactly. Any suggestions?

      Yoav Weiss (@Shopify)

      What you can do is add a WPT with a blocking script that document.write()s an HTML comment, and then have HTML that loads resources after that. Those resources would get preloaded, but never actually loaded.

      Then you can use resource timing to see what loads were triggers and assert that the behavior matches what you'd expect.

      I guess you could also just verify that resources from an unallowed base-uri origin are never loaded (again using resource timing)

      Andrew Paseltiner

      Acknowledged

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Andrew Paseltiner
      • Kouhei Ueno
      Submit Requirements:
        • requirement satisfiedCode-Coverage
        • requirement satisfiedCode-Owners
        • requirement satisfiedCode-Review
        • requirement satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: chromium/src
        Gerrit-Branch: main
        Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
        Gerrit-Change-Number: 7782696
        Gerrit-PatchSet: 5
        Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
        Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
        Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
        Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
        Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
        Gerrit-CC: Code Review Nudger <android-build...@prod.google.com>
        Gerrit-Attention: Andrew Paseltiner <apase...@chromium.org>
        Gerrit-Attention: Kouhei Ueno <kou...@chromium.org>
        Gerrit-Comment-Date: Mon, 01 Jun 2026 12:39:39 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: Yes
        Comment-In-Reply-To: Andrew Paseltiner <apase...@chromium.org>
        satisfied_requirement
        open
        diffy

        Chromium LUCI CQ (Gerrit)

        unread,
        9:42 AM (6 hours ago) 9:42 AM
        to Andrew Paseltiner, Code Review Nudger, Yoav Weiss (@Shopify), Antonio Sartori, android-bu...@system.gserviceaccount.com, Kouhei Ueno, chromium...@chromium.org, antoniosarto...@chromium.org, mkwst+w...@chromium.org, blink-revi...@chromium.org, arthursonzog...@chromium.org, blink-rev...@chromium.org, blink-...@chromium.org, kinuko...@chromium.org, loading-rev...@chromium.org

        Chromium LUCI CQ submitted the change

        Change information

        Commit message:
        Enforce CSP base-uri in HTML preload scanner

        The Blink HTML preload scanner failed to validate <base href> tags
        against the Content Security Policy 'base-uri' directive. This allowed
        an attacker with HTML injection capabilities to redirect speculative
        subresource fetches to an external origin, potentially leaking sensitive
        relative resource paths and the page URL.

        This patch updates TokenPreloadScanner to enforce the 'base-uri' CSP
        directive when processing <base> tags.

        Two approaches were considered for this fix:

        1. Scanner-side validation (Chosen): Validate the <base> tag immediately
        when the scanner encounters it. This ensures the scanner's internal
        base URL state is always CSP-compliant. It prevents all consumers
        of the scanner's base URL (including CSSPreloadScanner) from using
        a malicious origin. This approach requires copying CSP policies to
        the background scanner thread via CachedDocumentParameters.
        2. Fetch-side validation: Defer validation until PreloadRequest::Start()
        on the main thread. While this avoids copying CSP data, it would
        result in redundant CSP checks for every relative subresource
        discovered, and it would leave the scanner in a potentially
        vulnerable internal state that could be exploited by future scanner
        features.

        Scanner-side validation was chosen for its architectural consistency
        with how the main parser handles <base> tags and for its superior
        performance characteristics by avoiding redundant checks during resource
        resolution.
        Fixed: 502354038
        Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
        Reviewed-by: Antonio Sartori <antonio...@chromium.org>
        Commit-Queue: Andrew Paseltiner <apase...@chromium.org>
        Reviewed-by: Yoav Weiss (@Shopify) <yoav...@chromium.org>
        Cr-Commit-Position: refs/heads/main@{#1639348}
        Files:
        • M third_party/blink/renderer/core/frame/csp/content_security_policy.cc
        • M third_party/blink/renderer/core/frame/csp/content_security_policy.h
        • M third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
        • M third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
        • M third_party/blink/renderer/core/html/parser/html_preload_scanner.h
        • M third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
        Change size: M
        Delta: 6 files changed, 101 insertions(+), 2 deletions(-)
        Branch: refs/heads/main
        Submit Requirements:
        • requirement satisfiedCode-Review: +1 by Yoav Weiss (@Shopify), +1 by Antonio Sartori
        Open in Gerrit
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: merged
        Gerrit-Project: chromium/src
        Gerrit-Branch: main
        Gerrit-Change-Id: Ie157e2351740e65b9f9e1ba97142e39c167764a4
        Gerrit-Change-Number: 7782696
        Gerrit-PatchSet: 6
        Gerrit-Owner: Andrew Paseltiner <apase...@chromium.org>
        Gerrit-Reviewer: Andrew Paseltiner <apase...@chromium.org>
        Gerrit-Reviewer: Antonio Sartori <antonio...@chromium.org>
        Gerrit-Reviewer: Chromium LUCI CQ <chromiu...@luci-project-accounts.iam.gserviceaccount.com>
        Gerrit-Reviewer: Kouhei Ueno <kou...@chromium.org>
        Gerrit-Reviewer: Yoav Weiss (@Shopify) <yoav...@chromium.org>
        open
        diffy
        satisfied_requirement
        Reply all
        Reply to author
        Forward
        0 new messages