The Mystery of the “X”: Decoding HTTP Header Prefixes

If you have ever opened the “Network” tab in your browser’s developer tools or inspected a server response in Postman, you have likely seen them: a swarm of HTTP headers starting with the letter X.

X-Frame-Options, X-Powered-By, X-Request-ID, X-Forwarded-For.

They are everywhere, appearing in almost every web request you make. But what does the “X” actually stand for? Is it a mark of exclusion? A variable?

The answer lies in the early history of the web standards, a well-intentioned rule that backfired, and a massive course correction that changed how we build APIs today.

The Origin Story: “X” is for Experimental

In the early days of the web (specifically the era of HTTP/1.1), the Internet Engineering Task Force (IETF) needed a way to distinguish between standard headers and custom headers.

  • Standard Headers: officially documented fields like Content-Type, Host, or Cache-Control that every browser and server must understand.
  • Non-Standard Headers: Custom fields created by developers for specific applications or browser vendors testing new features.

The rule was simple: If you are creating a custom or experimental header, prefix it with X-.

The logic was that once an experimental header (e.g., X-Special-Feature) became a standardized feature, the “X-” would be dropped, and it would become simply Special-Feature.

The Problem: When Experiments Become Permanent

The “X-” convention failed because of a phenomenon known as deployment inertia.

Let’s look at the classic example: X-Forwarded-For.

This header was created to identify the original IP address of a client connecting through a load balancer or proxy. It started as a non-standard “X” header. It became incredibly useful. Everyone started using it—load balancers (AWS, Nginx), proxies (Squid), and web frameworks (Express, Django).

Eventually, the standards body said, “Okay, this is useful. Let’s make it a standard.” They created a standard header called Forwarded.

But nobody switched.

Why? Because millions of lines of code, thousands of firewalls, and countless logging scripts were already looking for X-Forwarded-For. Changing the name would break the internet.

So, the “experimental” header became the de-facto standard, forever stuck with an “X” that no longer meant anything.

The Turning Point: RFC 6648

In June 2012, the IETF released RFC 6648, titled “Deprecating the ‘X-‘ Prefix and Similar Constructs in Application Protocols.”

This document officially admitted that the “X-” convention was a bad idea. The recommendation for developers today is:

  1. Do not use “X-” for new headers.
  2. If you need a custom header, just name it distinctively (e.g., MyCompany-Tracking-Id or simply Auth-Token).
  3. You do not need permission to create a new header name, provided it doesn’t conflict with existing standards.

The “Living Fossils”: X-Headers You Still Need

Even though the “X-” prefix is deprecated for new headers, many legacy “X” headers are still critical for security and functionality. You cannot ignore them.

1. X-Content-Type-Options

This is a vital security header. Setting this to nosniff prevents browsers from “MIME-sniffing” a response away from the declared content-type.

  • Status: Essential.
  • WebSphere Note: As mentioned in our previous article, legacy systems like IBM WebSphere often require custom properties (com.ibm.ws.webcontainer.addXContentTypeOptions) to inject this header.

2. X-Frame-Options

Used to prevent Clickjacking attacks by stopping your site from being embedded in an <iframe> on another site.

  • Status: Obsolescent. It is being replaced by the Content-Security-Policy (CSP) directive frame-ancestors. However, many sites still use both for backward compatibility.

3. X-Permitted-Cross-Domain-Policies

As discussed in our cross-domain policy guide, this handles permissions for Adobe products (PDF/Flash).

  • Status: Niche but active for specific enterprise use cases.

4. X-Powered-By

Often sent by servers by default (e.g., X-Powered-By: Express or ASP.NET).

  • Status: Harmful. This header leaks information to attackers about your technology stack. It is a best practice to remove this header in your server configuration.

Is X-Content-Security-Policy Deprecated?

Yes.

When Content Security Policy (CSP) was being developed, Firefox used X-Content-Security-Policy and Chrome used X-WebKit-CSP.

Once the standard was finalized, browsers switched to supporting the clean header: Content-Security-Policy.

If you are still using the “X-” version of CSP, you are targeting browsers that are over a decade old. You should update your configurations to use the standard name immediately.

Summary for Developers

The “X” in HTTP headers is a history lesson in how difficult it is to change protocols once they reach mass adoption.

  • Reading headers: If you see an X- header, treat it as a custom or legacy field.
  • Writing headers: If you are building an API today, do not start your custom headers with X-. If you need to send a user ID, send User-ID or App-User-ID, not X-User-ID.

The “X” was meant to mark the temporary, but in the world of the web, nothing is more permanent than a temporary solution that works.


Leave a Reply

Your email address will not be published. Required fields are marked *

Interested in working with us? We'd love to hear more.

Tell us about your project, and we’ll send you detailed pricing and timeline information within 24 hours.

Interested in working with us? We'd love to hear more.

Tell us about your project, and we’ll send you detailed pricing and timeline information within 24 hours.