Why do HTTP servers forbid underscores in HTTP header names

They are not forbidden, it's CGI legacy. See "Missing (disappearing) HTTP Headers".

If you do not explicitly set underscores_in_headers on;, nginx will silently drop HTTP headers with underscores (which are perfectly valid according to the HTTP standard). This is done in order to prevent ambiguities when mapping headers to CGI variables, as both dashes and underscores are mapped to underscores during that process.


Underscores in header fields are allowed per RFC 7230, sec. 3.2., but are uncommon.