Understanding CSS :visited Privacy Restrictions
The CSS :visited pseudo-class allows developers to alter
the appearance of links a user has already clicked. Historically, this
capability introduced a severe vulnerability known as "history
sniffing," enabling malicious websites to silently harvest a visitor's
web browsing history. To close this loophole, modern web browsers
restrict :visited styles strictly to a small set of
color-related properties and lie to JavaScript about computed values,
neutralizing the threat while preserving a core user-experience feature
of the web.
The History-Sniffing Vulnerability
Before modern security restrictions were implemented, developers
could apply virtually any CSS property to the :visited
state, including background-image, font-size,
padding, and display.
Attackers exploited this behavior using two primary vectors:
- Network-based timing attacks: A page could inject
an invisible list of thousands of well-known URLs (such as banking
portals, social media platforms, or sensitive forums) and assign unique
background images to their
:visitedstates. Whenever a visited URL was matched, the browser requested the background image from the attacker's server, instantly logging which sites the visitor had frequented. - DOM-based layout checks: When styling properties
that altered box dimensions (like
display: noneor changingfont-size), JavaScript could query the DOM via properties likeelement.offsetWidthorelement.clientHeight. If the dimensions differed from the unvisited baseline, the script knew the user had visited that exact link.
Because these checks ran instantly and invisibly, a site could enumerate thousands of URLs per second to construct a detailed profile of a user's browsing habits.
The Color-Only Restriction
To eliminate layout-based leaks and network callbacks, modern browser
engines strictly limit :visited selectors to color
properties that do not alter the geometry of the page or trigger
external asset downloads.
Permitted properties are restricted to:
colorbackground-colorborder-color(including top, right, bottom, and left variants)outline-colorcolumn-rule-color- SVG
fillandstroke
Any attempt to apply layout-altering properties (such as
margin, padding, width, or
height) or resource-fetching properties (such as
background-image) to a :visited link is
completely ignored by the rendering engine.
Spoofing JavaScript APIs
Restricting styles to colors alone does not completely resolve the
problem, as JavaScript could theoretically use
window.getComputedStyle() to read the applied text or
background color and determine whether the link was visited.
To counter this, browsers implement "style spoofing." When JavaScript
requests the computed style of a visited link, the browser intentionally
returns the values of the unvisited link state. Scripting engines are
effectively blind to the :visited styling; only the
internal rendering pipeline receives the true color data used to draw
pixels on the screen.
Alpha Channel and Sibling Limitations
Browsers also restrict how transparency works with
:visited rules. If an unvisited link has a transparent
background, setting a solid background-color on
:visited could alter the perceived color of underlying
parent elements. Consequently, browsers enforce that the alpha channel
(opacity) of the visited state cannot be modified independently. The
browser uses the alpha component from the unvisited style to blend with
the visited color, preventing complex timing or composite-pixel
attacks.
Additionally, CSS combinators that depend on the visited state—such
as styling an adjacent sibling selector based on whether a preceding
link is visited (a:visited + span)—are disabled. Only the
link itself can take on visited color styles, ensuring that visited
status cannot leak outward into the rest of the document tree.