Great work!

XP to next level

BugEater

RFC Common Gotchas

After reading dozens of RFCs and testing hundreds of implementations, certain failure patterns repeat reliably. Knowing them in advance lets you target your tests at the most likely defects.

Gotcha 1: The Regex That Rejects Valid Input

The most common RFC conformance failure is a regex used as a validator that was written from memory rather than derived from the spec. These regexes typically:

  • Restrict the character set more than the RFC allows (missing +, !, #, ^, etc.)
  • Disallow structures that are valid per RFC (quoted strings, percent-encoding, IP literals)
  • Include constraints that weren't in the original spec (TLD length limits, minimum label count)

How to find it: take the full list of valid characters from the ABNF definition and test each one individually. For email local parts: !, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, }, ~. Any rejection is a bug.

Gotcha 2: Case-Sensitivity on Case-Insensitive Fields

Many RFC tokens are explicitly case-insensitive. HTTP method names are case-sensitive per RFC (GET ≠ get) but HTTP header names are case-insensitive (Content-Type = content-type = CONTENT-TYPE). Domain names are case-insensitive. MIME type names are case-insensitive.

Implementations frequently get this wrong in both directions:

  • Treating case-insensitive tokens as case-sensitive (rejecting Content-Type when expecting content-type)
  • Treating case-sensitive tokens as case-insensitive (matching GET and get when they should be distinct)

How to find it: submit the same token in all-uppercase, all-lowercase, and mixed case. Compare the results.

Gotcha 3: Missing Obsolete Syntax Support

Most RFCs that supersede older RFCs include "obs-" (obsolete) sections that define syntax valid in older versions. Implementations are required to accept obsolete syntax even though they should not generate it.

For email:

  • Whitespace between the local part and @ is obsolete but must be accepted
  • Comments (...) in addresses are obsolete but must be accepted
  • Folding whitespace in header fields is obsolete but must be accepted

Implementations written only from the current RFC without reading the obs- sections will reject valid obsolete forms.

How to find it: test with the obsolete forms from the obs- sections. If they are rejected, the implementation doesn't support the full required grammar.

Gotcha 4: Off-By-One Length Limits

RFC length limits are almost always maximum inclusive: "MUST NOT exceed 64 characters" means 64 is the maximum valid value. Implementations sometimes code >= 64 (should be > 64) or > 63 (correct) vs >= 64 (also correct but inverted).

How to find it: test exactly at the limit (should succeed), and exactly one over (should fail). Specifically:

  • Email local part: 64 characters should succeed; 65 should fail
  • Email full address: 320 characters should succeed; 321 should fail
  • Domain label: 63 characters should succeed; 64 should fail

A validator with an off-by-one error will reject 64-character local parts or accept 65-character local parts.

Gotcha 5: The "No TLD" Case

RFC 5322 does not require a TLD. An address like user@localhost is syntactically valid. RFC 5321 (SMTP transport) also allows it — mail to localhost is historically valid for local delivery.

Applications that validate for real internet use may reasonably require a TLD (for practical deliverability). But:

  • The application may be used in private network environments where localhost is a real mail destination
  • The application may consume email addresses from external systems that generate RFC-valid but TLD-less addresses
  • The error message "invalid email" is misleading when the actual rejection reason is "no TLD"

How to find it: submit user@localhost, user@mail, user@192.168.1.1 (IP literal). Document whether each is accepted or rejected and whether the behavior matches the stated requirements.

Gotcha 6: IP Address Literals in Domain

RFC 5321 allows IP addresses as the domain part in square brackets: user@[192.168.1.1] and user@[IPv6:2001:db8::1]. RFC 5322 also permits domain literals.

Most validators reject this entirely. For applications that process email addresses from any source (including API consumers, imported data, SMTP servers), rejecting IP-literal addresses may cause failures.

How to find it: test user@[127.0.0.1] and user@[IPv6:::1]. If accepted, verify the full address is stored correctly. If rejected, determine whether the rejection is intentional and documented.

Gotcha 7: The IDN Domain Double-Encoding Bug

When an application accepts internationalized domain names, it must handle them consistently:

  • Accept Unicode form: user@münchen.de
  • Accept punycode form: user@xn--mnchen-3ya.de
  • Store one canonical form
  • Display the correct form to the user

The double-encoding bug: the application converts münchen to punycode xn--mnchen-3ya, then applies punycode encoding again on the stored value, producing xn--xn--mnchen-3ya-... — invalid punycode.

How to find it: submit an email with a known IDN domain in Unicode form. Retrieve the stored value. Decode it. Verify it matches the submitted address exactly.

Quiz

RFC 5321 §4.1.2 says the local part is case-sensitive. An application treats User@example.com and user@example.com as equivalent. What is the correct assessment?

RFC 5322 permits header line folding (CRLF + whitespace). A test sends a folded header and the server returns HTTP 400. What should the tester conclude?

An RFC defines a maximum line length of 998 characters. What test cases should the tester derive?

RFC 5321 marks source routing as deprecated with SHOULD NOT. A system claiming RFC 5321 compliance rejects such addresses. What is the correct classification?