Using Client Hints to Detect Disparities
Every time a device makes an HTTP request to a server, it traditionally sends a User-Agent (UA) header along with each request. This header includes information about the device and its environment so that servers can enable analytics and customize responses. In practice, the User-Agent header passively exposes entropy that could be used in conjunction with other attributes to identify a particular user. An emerging standard named Client Hints (CH) has been introduced by the Google Chrome team that aims to enable access to the same information but in a more privacy-preserving way.
There are three types of client hints that a site can solicit: User-Agent Client Hints, Device Client Hints, and Network Client Hints. In this blog post, we will concentrate on the User-Agent Client Hints (UA-CH) specification. We will discuss how User-Agent Client Hints work, explore privacy-related features and concerns, and present how the partial adoption and incompleteness of this emerging standard can be used to detect disparities, unveiling bad actors and unwanted traffic by examining what we’ve found in the wild.
How Client Hints Work
There are two categories of client hints: low and high entropy. Low entropy hints include basic information that is shared by many users and are passed by default on every request. High entropy hints provide more details; and because they contain more informational value, they require a server to explicitly ask for them.
A server specifies the client hints it is interested in receiving by listing them in the Accept-CH response header. When a client receives the Accept-CH response header, it appends the listed client hint headers in subsequent requests.
Let’s take a look at how this works in the following example.
Step 1: The server asks for specific high entropy hints by listing them in the Accept-CH response header:
Accept-CH: Sec-Ch-Ua-Platform-Version, Sec-Ch-Ua-Bitness
Step 2: The browser sends back both the low entropy hints and the solicited high entropy hints in subsequent requests:
Sec-CH-UA: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"Sec-CH-UA-Mobile: ?0Sec-CH-UA-Platform: "macOS"Sec-CH-UA-Platform-Version: "12.6.0"Sec-CH-UA-Bitness: "64"
Historically, both low and high entropy types are aggregated in the UA string and sent to servers by default for first- and third-party requests.
Here is an example of how a UA string looks on a request coming from a Chrome browser running on a Mac OS device:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/106.0.5249.62 Safari/537.36
The table below maps the values included in the UA string to their respective CH entropy category.
Mac OS X
Full software version
Operating system version
Intel Mac OS X 10_14_6
The UA-CH specification aims to reduce the UA string granularity in favor of more limited user information and protects access to high-entropy hints. The specification also states that client hints are only to be delivered over secure TLS connections. In addition, client hints are only sent on same-origin requests. To allow cross-origin requests (e.g, https://thirdparty.example/tracking.js), implementers must explicitly delegate permission via the Permissions-Policy header.
Conversely, these privacy benefits can also be abused. Client hints provide an additional way to access identifying values. For example, a first party could instruct your browser to send all values to third parties in the background, which might otherwise require injecting scripts, resulting in more identifying information being shared with more parties without most users realizing it.
Alongside of this, systems such as proxies, CDNs, and firewalls that terminate TLS can have access to this information. It’s important to carefully read and understand the privacy policies around the components that underpin your infrastructure before you consider adopting this standard.
User agent strings have long been used to provide detection specialists a way to spot oddities that can help identify risky behavior, reduce fraud, and spot security problems. However, checking the UA string is a well-known technique and actors will often attempt to masquerade their activity by using a legitimate UA string.
One of the advantages of looking at client hints is that it is still experimental. This means for the time being, browsers that support client hints continue to send both the customary UA string and client hints along with each request. Because they’re still in the experimental phase, client hints are less known and commonly overlooked. Combining the CH information with the UA string can be used to detect disparities, unveiling bad actors and unwanted traffic.
For instance, Burp Suite, a very popular penetration testing tool, is shipped with its own Chromium web browser. The default UA string currently identifies as:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/106.0.5249.62 Safari/537.36
This leads to a detectable disparity if the user isn’t running on Windows, as illustrated in the following request:
GET /headers HTTP/2Host: user-agent-client-hints.glitch.meSec-Ch-Ua: "Not;A=Brand";v="99", "Chromium";v="106"Sec-Ch-Ua-Mobile: ?0Sec-Ch-Ua-Platform: "macOS"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/106.0.5249.62 Safari/537.36
Using this information, we examined attack data over a one-hour period and discovered that about 8% of all signaled requests were sent with a UA string that resembled the default UA string of Burp's embedded browser. Further analysis revealed that over 90% of requests with client hint disparities representing known operating systems advertised Linux as the platform.
One could assume this attack traffic is originating from Burp running on a Kali Linux – an open-source Debian-based Linux penetration testing distribution. Using this information alongside other indicators like JA3 could provide a higher level of confidence.
Further investigation also revealed attack payloads being injected into client hint headers, including SQL Injection, Command Injection and Cross-Site Scripting (XSS). It’s important to be aware that client hints are HTTP header fields, so there is nothing preventing a user from manipulating these fields just like they do with the UA string. As the CH headers are in fact user controllable, this can lead to a number of issues. An attacker may be able to leverage this vector for exploiting a variety of flaws if the server implicitly trusts the CH headers and neglects to properly validate or escape it.
Client Hints is a new emerging standard still in the experimental stage. Due to its partial adoption and incompleteness, it provides some interesting areas for research. Its privacy-preserving features provide a number of benefits, but there are also concerns about the potential misuse of those advantages. And although this standard is becoming more widely adopted, the traditional approaches of transmitting low and high entropy device information are still in use. When combined, this data can produce a number of surprising discoveries.