cybersecurity · intermediate · ~15 min

Bounded URL Percent-Decoder

Implement robust percent-decoding with hex validation and null-byte injection guards.

Challenge

URL percent-decoding (%20 -> ' ', %2F -> '/') processes untrusted web parameters. Malicious inputs with truncated percent escapes (e.g. "%2") or null-byte injections (%00) can cause out-of-bounds reads or path traversal.

Your Task

Implement:

int decode_url_component(const char *src, char *dest, size_t dest_cap, int allow_null_byte);

Rules

  1. If src == NULL, dest == NULL, or dest_cap == 0, return -1.
  2. Scan src character by character:
    • '+' is converted to space ' '.
    • '%' must be followed by two hexadecimal characters [0-9a-fA-F]. If fewer than 2 characters remain, or if either character is not valid hex, return -1.
    • Decode hex value into a single byte.
    • If decoded byte is 0x00 and allow_null_byte == 0, return -1 (poison null byte detected!).
    • Any other character is copied as-is.
  3. If the decoded string (plus NUL) does not fit within dest_cap, return -1.
  4. On success: NUL-terminate dest and return 0.

Example

char out[32];
decode_url_component("hello+world%21", out, sizeof(out), 0); // returns 0, out == "hello world!"
decode_url_component("admin%00.txt", out, sizeof(out), 0); // returns -1 (null byte poison rejected!)

Input format

src: URL encoded string; dest: output buffer; dest_cap: capacity; allow_null_byte: int flag.

Output format

Returns 0 on success, -1 on invalid hex, null-byte injection, or overflow.

Constraints

Zero dynamic allocations. Strict hex conversion.

Starter code

#include <stddef.h>

int decode_url_component(const char *src, char *dest, size_t dest_cap, int allow_null_byte) {
    (void)src; (void)dest; (void)dest_cap; (void)allow_null_byte;
    return -1;
}

Common mistakes

Reading past end of string on truncated percent escape; missing NUL byte termination.

Edge cases to handle

Truncated escape (e.g. "%") returns -1; invalid hex "%ZZ" returns -1; %00 rejected when allow_null_byte==0.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.