The specification is a promise, Part 1: what contracts look like
An RFC is a contract. A man page is a contract. A vendor specification is a contract. Security researchers read contracts looking for ambiguity, latitude, and the edge cases the author did not think about.
Every security researcher should read more specifications. Not to memorise them — though familiarity accumulates — but to develop the specific reading mode that finds the gaps. A specification is a statement of intent, and the gap between intent and implementation is where vulnerabilities live. But before you can read for the gap, you need to understand what the contract says.
The word "contract" is used deliberately. A specification — whether RFC, IEEE standard, POSIX definition, or vendor documentation — defines a relationship. The implementer promises to behave according to the specification. The user of the implementation relies on that promise. When the promise is kept, the system behaves predictably. When it is not, something can go wrong. Understanding the contract is the prerequisite to understanding when it is being broken.
What MUST and SHOULD actually mean
RFC 2119 defines a vocabulary used in most IETF specifications: MUST, SHOULD, MAY, MUST NOT, SHOULD NOT. These have precise meanings. MUST is an absolute requirement. SHOULD is a recommendation that may be ignored in specific, documented circumstances. MAY is an option.
For a security researcher, the distinction between MUST and SHOULD is important because it defines what an implementer is permitted to do. A SHOULD requirement can be legitimately ignored — but the circumstances under which it may be ignored are often underspecified, and an implementation that ignores a SHOULD when it should not may produce incorrect behaviour that the specification, technically, permitted. This is not a vulnerability in the specification. It is latitude that an implementer has used badly, and it can matter.
The word MAY is worth particular attention. A feature that is optional is a feature that some implementations include and some do not, with undefined consequences for interoperability at the edges. The optional feature becomes a security boundary the moment one implementation's inclusion of it changes the security properties of a system that interacts with another implementation that omits it.
Reading for ambiguity
The sentences in a specification worth rereading are the ones that seem clear on first reading but turn out to contain unresolved questions. "The server shall verify the client's identity before proceeding." Verify how? Against what? With what tolerance for failure? "The implementation shall ensure that the buffer is of sufficient size." Sufficient for what? Determined when? By whom?
These are not pedantic questions. They are the questions that implementers have to answer, and the answers they choose — often without realising that a choice is being made — define the implementation's actual security properties. A specification that does not answer them has delegated those security decisions to implementers, which is sometimes intentional and sometimes not.
The implementation latitude problem
A well-written specification minimises implementation latitude for security-relevant decisions. It does not leave the question of what to do with a malformed input to the implementer's judgment. It defines the required behaviour precisely. This is hard, because specifications are written by people who are thinking about the common case, and the common case rarely includes the adversarial input.
A specification that says "implementations SHOULD reject malformed inputs" has, effectively, permitted implementations to accept them. An implementation that accepts malformed inputs "for compatibility" is compliant with the specification, technically. Whether it is secure depends on what those malformed inputs cause the implementation to do — a question the specification has declined to answer.
Part 2 will look at what happens when the gap between specification and implementation becomes a security boundary. For now: read the specification. Read it slowly. Read the SHOULDs as questions. Read the MAYs as unexploded ordnance.
A specification is a PING sent across time from the author to every future implementer. How precisely it was written determines how clearly that message arrives. The gaps in the transmission are visible in the implementations that followed it — if you know how to read both documents at once.