#896: Partitioning :visited links history
Discussions
Discussed
Nov 13, 2023 (See Github)
Amy: seems good, what's the catch?
Peter: I know there are other mitigations to using visited links as fingerprinting. i wonder if this is necessary if those other mitigations are used. this has impact to the user. not sure this is a benefit to the user.
Amy: it's a trade-off... but there is a citation that we don't understand how people feel about links being styled differently.
Peter: I rely on it.
Lea: we've learned not to rely on it but when it is there it can be quite useful.
Lea: this partitions history based on origin... if we wanted to implement this using JS we could do it... If you can have the union of these 2 then there are few visited links tyou would miss having...
Peter: i remember years ago David Baron had a proposal letting the style of visited links happen but relying on JS...
Lea: very restricted styling that can be done - only colors really... The point of this proposal is that it's a normal pseudoclass...
... tbc ...
Discussed
Dec 11, 2023 (See Github)
Amy: we definitely discussed this... can't find minutes
Peter: i remember being concerned about : don't we already do this? but it looks like they are taking that into account and going beyond the protections we have...
Amy: was Lea's concern that this would make visited links useless to end users?
Peter: concerns about ... most visited links would not show up as visited.. Triple keying - target, domain and top level domain...
Amy: my perspective is that's probably a reasonable trade-off for not leaking your history... but don't have a good sense of how useful visited links state is for most other people
Peter: personally - search results - visited links are useful - that would not break. Similar a wikipedia site - that would not break. It does break if it's cross-site. If I visit a site where I've never clicked on a link
Dan: Say you visit a link on a social media site to an article in a blog.
Peter: and then you visit another social media site has a link to the same article - it would not show as visited. Users will lose some utility and some may be confused but it won't be the most common cases where we expect visited links to work.
Dan: what do other browsers think of this? No signals. We could say it looks good, we understand the tradeoffs, what feedback is there from other browsers?
Peter: agree we should ask for feedback from other browsers. Not sure we should say it looks good yet, some concerns about user expectations
Peter to leave feedback
Comment by @plinss Dec 11, 2023 (See Github)
Taking a look at this we have some concerns about user experience and expectations, specifically when users will be seeing visited links appearing as unvisited. We understand this may not be on the majority of use cases, but wonder if any research has been done about the scope of the impact and user reactions.
Also, is there any feedback from other engine implementers?
Comment by @kyraseevers Dec 13, 2023 (See Github)
Thanks for the question! In an upcoming implementation phase, we will write a "signal loss" metric. This metric will allow us to understand what percentage of links that were styled as :visited in the current model would no longer be styled as :visited in the partitioned model. We'll keep you updated with those results.
We haven't solicited official positions from other browsers yet, but we have had positive feedback and interest from other browsers at TPAC and WebAppSec WG meetings.
Thanks!
Discussed
Dec 18, 2023 (See Github)
No signals from other browsers, so marking 'multi-stakeholder?' We should probably punt/close and ask them to re-open this one, wait for data from experimentation.
Comment by @plinss Dec 20, 2023 (See Github)
We appreciate the problem you're trying to solve and agree that this is a really important privacy issue. Architecturally, this isn't a huge issue. We want to make sure this is good for users. We think this is fine for experimentation but we would like to see some results of that experiment regarding the impact on users.
We'd also like there to be multi-stakeholder consensus on this to avoid user confusion.
We're going to close this for now. When you have more info to share, can you please re-open this or open a new issue?
Comment by @kyraseevers Feb 11, 2025 (See Github)
Hi TAG!
I’m re-opening this issue, as you requested, to give an update regarding our implementation and experimentation for partitioned :visited links.
First, we have heard positive signals from Firefox and Safari regarding partitioning. Based on this and other feedback from TPAC, we believe that there is multi-stakeholder interest in the feature and plausible consensus on the approach.
Second, we have had positive results from our experiments as well. We’ve run multiple experiments on a percentage of both pre-release and stable traffic since July 11th, 2024 (Chrome Version 128). In addition to nearly 6 months of experiment data, we also began a Developer Trial and added the corresponding self-links flag to ExperimentalWebPlatformFeatures in Chrome Version 133.
During this time, our only bug report was regarding support for context clicks (i.e. right clicking on a link and making it turn purple in a partitioned environment). This functionality was added in Chrome Version 133 and will be part of the model we ship. During these six months of experiments, there have been no changes to Chrome vital metrics including memory footprint, rendering speed, or loading performance.
Finally, we have found that this partitioning model still captures a good chunk of visited links, within an acceptable threshold. Considering that the goal of this feature is to get rid of any “global” :visited state available to bad actors, we expected a portion of visited links to no longer be shown as :visited under the new partitioning model. We do not believe that user experience is compromised by this reduction, because the core behavior associated with :visited links still remains - “when I click on a link, it turns purple.” What has gone away, in the partitioned model, are all the other times a link turned purple, on sites that a user had never visited before - which was behavior that users may have even found surprising or confusing. Ultimately, we feel this is an acceptable change in user experience to improve user privacy and security.
Thanks! (Also @plinss or @rhiaro the UI says I don't have permission to reopen the issue, so would you be able to do that for me? - thanks so much)
Discussed
Mar 17, 2025 (See Github)
During Breakout C, Marcos figured out this issue was reopened but the resolution label is still there. Should it be closed and a new issue be created?
Jeffrey: Agree with Marcos. How do others feel about this?
Dan: It seemed liked a good change.
Jeffrey: Shall we suggest satisfied? Earlier it was satisfied with concerns. Looks like they got through the concerns. Hearing no objections, I'd say we're satisfied.
Comment by @marcoscaceres Mar 19, 2025 (See Github)
Looks like implementers are positive on this approach.
However, we will review in the plenary.
Discussed
Mar 31, 2025 (See Github)
See proposed comment at https://github.com/w3ctag/meetings/blob/gh-pages/2025/03-24-minutes.md#breakout-b. Jeffrey's pre-meeting proposal:
Jeffrey: I think this could be satisfied
because they're using the partitioning everyone's converging toward.
Martin: Partitioning isn't converged yet, which is why they need to refer to the common concepts.
Marcos: Testing?
Jeffrey: Something in the I2S thread about difficulty with tests.
Martin: Should be straightforward.
Dan: Tab's saying it's flaky because it's not synchronous.
Martin: That's an implementation issue, which shouldn't concern us.
Jeffrey: Mention tests in the comment?
Marcos: CSSWG hasn't been great about adding WPTs with spec wording.
satisfied
with:
We're excited that this is moving forward and that the specification has moved into https://drafts.csswg.org/selectors-4/#visited-privacy.
We encourage the CSSWG to refer to the same partitioning concepts we are using for other site-level state, instead of redefining the partition key in the Selectors spec. The three-level key does match what we understand to be used elsewhere, but you should cite either https://storage.spec.whatwg.org/#storage-keys or https://privacycg.github.io/storage-partitioning/.
We also would like to ensure that proper web platform tests are landed for the corresponding specification changes. (Marcos commented about tests.)
Comment by @lknik Mar 31, 2025 (See Github)
This proposal fixes a long-term web privacy vulnerability that has roots in the web platform fundamentals. The risk is known for about 25 years, with numerous demonstrations. It's time to solve this once and for all.
Comment by @jyasskin Apr 1, 2025 (See Github)
Note that there's a draft specification in https://drafts.csswg.org/selectors-4/#visited-privacy. According to https://groups.google.com/a/chromium.org/g/blink-dev/c/8dZqt8JuLdc/m/qwyVRQskAgAJ, that hasn't merged to the main spec yet because it hasn't been shipped in a stable browser yet.
Comment by @marcoscaceres Apr 1, 2025 (See Github)
I guess the only thing to call out here is that there should be web platform tests that show partitioning working as expected.
Comment by @martinthomson Apr 1, 2025 (See Github)
We're excited that this is moving forward and that the specification has moved into https://drafts.csswg.org/selectors-4/#visited-privacy.
We encourage the CSSWG to refer to the same partitioning concepts we are using for other site-level state, instead of redefining the partition key in the Selectors spec. The three-level key does match what we understand to be used elsewhere, but you should cite either https://storage.spec.whatwg.org/#storage-keys or https://privacycg.github.io/storage-partitioning/.
OpenedSep 12, 2023
こんにちは TAG-さん!
I'm requesting a TAG review of “Partitioning :visited links history.”
The goal of this feature is to eliminate user browsing history leaks by styling anchor elements as :visited if and only if they have been clicked from this top-level site and frame origin before. On the browser-side, this means that the data structure storing the :visited links would be partitioned via "triple-keying", or by storing the following for each visited link: <link URL, top-level site, frame origin>. By only styling links that have been clicked on this site and frame before, the many side-channel attacks that have been developed to obtain :visited links styling information would become obsolete, as they would no longer provide sites with new information about users.
Further details:
We'd prefer the TAG provide feedback as: 💬 leave review feedback as a comment in this issue and @-notify: kyraseevers, arturjanc, miketaylr
Security and Privacy self-review
(1) What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary?
This feature does not expose new information to websites or other parties. It aims to restrict the information exposed by :visited links. The difference between unpartitioned and partitioned :visited links, is that unpartitioned :visited links exposes global user-browsing history state, whereas, partitioned :visited links only exposes what links have been visited from this site before (information that is already known to sites via other methods).
(2) Do features in your specification expose the minimum amount of information necessary to enable their intended uses?
Yes, no new information is exposed.
(3) How do the features in your specification deal with personal information, personally-identifiable information (PII), or information derived from them?
This feature does not deal with personal information, PII, or any information derived from them.
(4) How do the features in your specification deal with sensitive information?
It does not handle sensitive information.
(5) Do the features in your specification introduce new state for an origin that persists across browsing sessions?
No, there isn’t any new state introduced.
(6) Do the features in your specification expose information about the underlying platform to origins?
No, this feature does not expose information about the underlying platform.
(7) Does this specification allow an origin to send data to the underlying platform?
Yes - the link URLs are passed to the platform, however, this is already done by the current :visited links implementation.
(8) Do features in this specification enable access to device sensors?
No, there is no access to device sensors.
(9) Do features in this specification enable new script execution/loading mechanisms?
No, there aren’t any new script execution/loading mechanisms.
(10) Do features in this specification allow an origin to access other devices?
No, this feature does not allow an origin access to other devices.
(11) Do features in this specification allow an origin some measure of control over a user agent’s native UI?
Yes, but no more than the existing :visited link styling capabilities.
(12) What temporary identifiers do the features in this specification create or expose to the web?
None - no new identifiers are created or exposed.
(13) How does this specification distinguish between behavior in first-party and third-party contexts?
First and third parties BOTH must abide by triple-key partitioning. However, there are some edge cases where a first-party embed may display a site not previously visited in that frame (i.e. when a site embeds a iframe containing itself and the user has clicked on a link on this site in a previous visit, the link in both the top-level frame AND the iframe will be styled as visited.)
(14) How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode?
In private browsing/incognito mode, :visited links are not styled at all.
(15) Does this specification have both "Security Considerations" and "Privacy Considerations" sections?
Selectors 4 has some existing language for both privacy and security considerations - https://www.w3.org/TR/selectors-4/#priv-sec
(16) Do features in your specification enable origins to downgrade default security protections?
No, all origins are partitioned equally.
(17) How does your feature handle non-"fully active" documents?
History is only written to the :visited links database and hashtable once navigation is complete. We are not making any alterations to the timing of when the renderer requests the :visited status of a given link during CSS parsing.
(18) What should this questionnaire have asked? Nothing to add.