w3c / w3c/csswg-drafts

[selectors] Solve :visited once and for all

Open
#3,012 44 comments 27 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

selectors-4
Dominant language
Bikeshed
Stars
4.9k
Forks
816
PR merge metrics
PR metrics pending

Description

In https://github.com/w3c/css-houdini-drafts/issues/791 @deian explains a new channel for high-bandwidth leaking of :visited state by observing repaints with the Houdini Paint API. There doesn't appear to be a reasonable way to shut this down under the current regime of partial-censoring of :visited - the current fix for Chrome is to just disallow the paint() function from being used at all on any <a> element or its descendants.

We really need to finally define a sensible model of :visible-state visibility, based on what information would have already leaked to the page via standard, unpluggable channels; then we can finally drop all the silliness around :visited and just treat it as a plain, ordinary pseudo-class that allows all properties to be used in the standard fashion.

  1. At minimum, same-origin visitedness is always visible to the page, as the server can track its own cross-links, assuming standard tracking mechanisms exists (cookies, sufficiently high-entropy user identification, etc). So all same-origin links should report :visited.

  2. Cross-origin inbound links are always visible to the page if the Referer header was sent in the request.

  3. Cross-origin outbound links are always visible to the page if the user visited that link from this origin, as there are a multitude of ways to track outbound links (JS auditing, <a ping>, link shorteners, etc).

  4. Any others?


If a link matches one of the conditions above, and is visited, it's allowed to match :visited; otherwise it never matches :visited. So, what's the cost/benefit of each of the conditions above?

1 is easy to apply and non-controversial. It also probably represents at least half of the benefit of :visited styling for the user - they can tell when they've already visited a given page on a site.

But I don't think it's a whole lot more than half - there is a lot of benefit to knowing what links you've visited from a given page, regardless of origin. (Think of clicking thru each of a list of outbound links, such as in a forum post, or in Google search.) So I think 3 is most of the rest of the benefit, but probably the most controversial in terms of theoretical privacy (even if it's nil in practical privacy for the vast majority of users). I think it's reasonable for browsers to nix this condition if the user is blocking script, as that's the primary tracking mechanism.

I think 2 is of relatively minor benefit, but it lies inbetween 1 and 3 in terms of privacy leaking. Some UAs do offer the ability to block Referer, and of course they would then block this visitedness channel, but otherwise it's common and not a big deal. It's just that most cross-origin pages won't have a link back to the page you visited from; the exception is things like weird cross-site web puzzles, or old-school webrings.

Are there any other conditions that would allow us to safely expose :visited state unreservedly?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the linked Houdini Paint API issue and the proposed conditions for exposing :visited state. The issue does not name files or tests; the work is done when the CSS Working Group agrees on a sensible visibility model and its privacy trade-offs.

Written by the indexing model from the issue text.

Assessment

Tech stack
css
Domain
frontend, security, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.