cybersecurity · intermediate · ~15 min · safe pentest lab
Practice deny-by-default validation of attacker-influenced input: bounds-check length before indexing, guard against NULL pointers, and perform case-insensitive exact matching without a buffer overrun. Reinforces why absent hardening headers (HSTS, CSP, X-Frame-Options) leave an endpoint exposed.
When auditing an HTTP response, a defender checks whether the server sent the hardening headers that browsers rely on. Three matter here:
If any of these is absent, the endpoint is exposed. Your job is to scan a list of the response's header names and report which required headers are missing as a bitmask: bit0 = HSTS, bit1 = CSP, bit2 = X-Frame-Options. 0 means all present.
The asset is the header-name array baked into the grading harness — a fixed, in-memory buffer. You never touch a live target, a socket, or the filesystem. HTTP header names are case-insensitive, so content-security-policy and Content-Security-Policy are the same header.
The insecure assumption to avoid: trusting that the caller handed you a valid, non-empty array. names may be NULL, n may be zero or negative, and individual entries may be NULL. Deny by default: treat anything you cannot positively confirm as missing (all three bits set), and bounds-check n before you ever index the array.
missing_security_headers(only_csp, 3) -> 5
where only_csp contains just Content-Security-Policy among other unrelated headers, so HSTS (bit0) and X-Frame-Options (bit2) are missing: 0b101 = 5.
names: a pointer to an array of n C-string header names (may be NULL; individual entries may be NULL). n: the number of entries (may be 0 or negative). Comparison is case-insensitive.
An int bitmask of ABSENT required headers: bit0 Strict-Transport-Security, bit1 Content-Security-Policy, bit2 X-Frame-Options. Return 0 when all three are present.
C11, freestanding function (harness supplies includes). No allocation, no I/O, no network, no filesystem. Match header names case-insensitively and exactly (a prefix like 'Content-Security-Policy-Report-Only' is a DIFFERENT header and must not count). Reject NULL array and n <= 0 by returning 0x7. Never dereference a NULL entry or read out of bounds. 0 <= valid n <= a few dozen.
int missing_security_headers(const char *const *names, int n)
{
/* TODO: inspect names[0..n) case-insensitively and return a bitmask
of the ABSENT required headers (bit0 HSTS, bit1 CSP, bit2 XFO).
Deny by default: reject NULL / non-positive n before indexing.
This stub is insecure/incorrect: it claims everything is present. */
(void)names; (void)n;
return 0;
}Indexing names[i] before checking n <= 0 or names == NULL (out-of-bounds / NULL deref). Using strcmp (case-sensitive) so 'content-security-policy' is missed. Using a prefix/substring match so 'Content-Security-Policy-Report-Only' wrongly satisfies CSP. Starting the mask at 0 and setting bits for present headers instead of clearing bits for present ones. Dereferencing a NULL array entry.
n == 0 or n < 0 (return all-missing, never index); names == NULL (return all-missing); a NULL entry inside the array (skip, do not dereference); mixed/upper/lower case names (must still match); a header whose name has a required header as a prefix (e.g. Content-Security-Policy-Report-Only) must NOT count as the required header; duplicates and unrelated headers.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.