cybersecurity · intermediate · ~25 min

Redact email addresses in a log line

Pattern-based string rewriting in place; respecting buffer bounds.

Challenge

Strip email addresses from a log line before it ships to a centralised service — the smallest example of PII redaction every production logger eventually needs.

Task

Implement void redact_emails(char *line) that mutates line in place, replacing every email-like substring with the literal text [redacted].

An email-like substring is a maximal run matching this loose pattern:

  • one or more characters in [A-Za-z0-9._+-] (the local part)
  • a literal @
  • one or more characters in [A-Za-z0-9.-] (the domain)
  • a literal .
  • two or more letters in [A-Za-z] (the TLD)

Input

  • line: a NUL-terminated, writable buffer. The grader passes a fixed line. Assume strlen(line) < 2048.

Output

No return value. line is rewritten in place with every email replaced by [redacted].

Example

"alice@example.com signed in"                       ->   "[redacted] signed in"
"User bob.smith+spam@example.co.uk forgot password" ->   "User [redacted] forgot password"
"no email here"                                     ->   "no email here"
"two: a@b.com and c@d.io"                           ->   "two: [redacted] and [redacted]"
"weird a@b.x stuff"                                 ->   "weird a@b.x stuff"   (1-letter TLD: not an email)

Edge cases

  • No email present: leave the line unchanged.
  • Multiple emails: redact all of them.
  • A one-letter TLD (a@b.x) does not match.
  • Bare @, a@, @b: not emails.

Rules

  • Rewrite in place (a local scratch buffer is fine); do not heap-allocate.

Why this matters

Shipping logs to a centralised analytics service often runs afoul of privacy laws (GDPR, CCPA) unless personally identifiable information is stripped first. Email redaction is the smallest example of the kind of pipeline-stage redaction that every production logger eventually needs.

Input format

A NUL-terminated, writable line (assume length < 2 KB).

Output format

No return value; line is mutated so every email becomes [redacted].

Constraints

Rewrite in place; no heap allocation; a 2+-letter TLD is required to match.

Starter code

void redact_emails(char *line) { /* TODO */ }

Common mistakes

Replacing only the first match. Allocating a new buffer (the contract is in-place).

Edge cases to handle

No email; multiple emails; email at the very start or end; pathological-looking strings that aren't actually emails (@, a@, @b).

Complexity

O(strlen(line)).

Background lessons

Up next

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