Skip to main content

How to Validate HTTP Headers and Clean a Header List

Check a list of HTTP headers for the Name: value shape, catch malformed lines, flag bad field-name characters, and export a clean header set, all in the browser.

Published By Li Lei
#http #headers #validation #developer-tools #web

How to Validate HTTP Headers and Clean a Header List

Every HTTP header follows the same small grammar, and the easiest way to break a config is to violate it by one character. A header line is a field name, then a colon, then the value. The field name is made of token characters: letters, digits, and a handful of symbols like - and _. No spaces. No colons inside the name. So Content-Type: text/html is well-formed, while Content Type: text/html is not, because the space splits the name into two pieces. A line with no colon at all, like Cache Control max-age=600, has no place where the name ends and the value begins.

These mistakes are quiet. A header list copied from a proxy config, a support ticket, or a screenshot of dev tools looks fine until something downstream rejects it. The HTTP Header List Validator reads that list line by line, decides which rows have the Name: value shape and which do not, and hands back a report with a reason next to every row. Everything runs in your browser, so the config you paste never leaves the tab.

What a valid header line actually requires

Strip the protocol down and a header field has three parts: the name, a colon delimiter, and the value. The name is the part that has rules. It must be one unbroken run of token characters, which means letters and digits plus a short set of symbols, and crucially it cannot contain a space or a colon. The colon ends the name; whatever follows is the value.

That single rule explains most of the failures people hit:

  • Content Type: text/html is malformed because the space inside the name is illegal. Browsers and servers would read Content as the whole name and choke on the rest.
  • X-Frame Options: DENY is the same bug with a missing hyphen. The real header is X-Frame-Options, one token, and the space turns it into two.
  • Cache Control max-age=600 has no colon, so there is no delimiter and no value boundary at all.
  • A header with an empty name, like : nosniff, fails because there is nothing before the colon to name the field.
  • A value carrying a raw control character (a stray tab or newline byte that survived a copy) is suspect, since header values are meant to be printable text.

What this tool checks, exactly

Per the tool's own description, the parser reads each line and looks for a valid Name: value shape. It flags the broken ones with a reason, so a missing colon, an empty field name, or a control character in the value shows up as invalid instead of slipping through unnoticed. Those three checks are the core: is there a colon delimiter, is there a non-empty field name before it, and is the value free of control characters.

On top of the pass/fail check, the tool does the cleanup work you would otherwise do by hand. You can keep unique rows only, or preserve the invalid rows so they stay visible for review. You can sort the normalized output. And you can switch the export between CSV, JSON, Markdown, SQL IN, TypeScript union, and plain lines, then download the exact artifact you need. Sensitive profiles such as cards and JWTs mask their values in the output while still giving you a useful validation signal, which matters when a captured header set carries an Authorization token you would rather not paste into a shared document.

One honest limitation worth repeating from the tool's notes: validation checks shape, not truth. A header that passes the Name: value test is well-formed, but that says nothing about whether the directive is correct policy or whether the resource it describes exists. Treat a green row as "this line parses," not "this header is right."

A worked example

Here is a small captured header set with a mix of clean and broken lines. Paste a block like this:

Content-Type: application/json
Content Type: text/html
X-Frame-Options: DENY
X-Frame Options: SAMEORIGIN
Cache-Control: no-store
Cache Control max-age=600
Strict-Transport-Security: max-age=31536000

The validator walks each row and produces a report with a reason column. Conceptually the output looks like this:

| line | row | valid | reason | |---|---|---|---| | 1 | Content-Type: application/json | true | OK | | 2 | Content Type: text/html | false | space in field name | | 3 | X-Frame-Options: DENY | true | OK | | 4 | X-Frame Options: SAMEORIGIN | false | space in field name | | 5 | Cache-Control: no-store | true | OK | | 6 | Cache Control max-age=600 | false | no colon delimiter | | 7 | Strict-Transport-Security: max-age=31536000 | true | OK |

Four rows pass, three are flagged, and each failure keeps its own reason so you can go fix the source. Rows 2 and 4 are the same bug, a stray space breaking a name that should be one token, and row 6 has no colon at all. With "include invalid" turned on, those three stay in the report rather than being silently dropped, which is the whole point when you are cleaning a spec a teammate has to trust.

When I reach for it

I keep a header allowlist in a release checklist, and the version that bites me is always the one a human edited in a hurry. The last time I shipped a broken one, someone had typed X-Content-Type Options: nosniff with a missing hyphen, and it sat in the file for a week because it looked close enough. Now I paste the list in before every release, flip on "include invalid," and read the reason column top to bottom. The space-in-name and missing-colon rows jump out immediately, I fix them at the source, dedupe, sort, and export the clean set as JSON for the config. The whole pass takes under a minute, and because it runs locally I do not think twice about the Authorization line that comes along with a captured set.

Cleaning a captured or config header set

A real-world header list rarely arrives clean. It comes out of a proxy config with comments, out of a browser's network tab with duplicates, or out of a chat thread where someone pasted half of dev tools. The workflow is the same each time: paste the raw text, let the validator flag the malformed rows, fix the offenders, then dedupe so a header that appears three times across pasted snippets collapses to one. Normalize first if the source is copied web text, because hidden whitespace travels with it and can make two identical-looking rows compare as different. When you want an audit trail, download the CSV or Markdown with line numbers rather than copying only the final list, so a reviewer can trace each header back to where it came from.

If your headers came out of a larger blob of text, start one step earlier with the HTTP Header Extractor to pull the header lines out first, then bring the result here to validate the shape. For header sets that are well-formed but inconsistently cased, the normalizer and deduplicator tools in the same family round out the cleanup before you hand the list off.

A header allowlist or spec is a short list, usually a few hundred lines at most. That is exactly the size where a one-character mistake hides best and where a quick shape check pays for itself.


Made by Toolora · Updated 2026-06-13