cybersecurity · intermediate · ~15 min · safe pentest lab

Defensive Password Strength Meter

Practice turning a security policy into safe, bounds-checked C: validate the pointer before use, compute length by scanning to the NUL terminator, classify characters without reading out of range, and enforce an exact-match denylist rather than a loose prefix check.

Challenge

Password strength, the defensive way

You are hardening an account-creation flow. The asset is the user's account; the threat is an attacker who guesses or brute-forces weak passwords. The insecure assumption teams keep making is "any non-empty password is fine" — that lets in password, 123456, and 6-character lowercase strings that fall in seconds.

Your job is to build a strength meter, not a cracker. It never touches a network, filesystem, or live account — it scores one C string that lives in a fixed buffer inside the grading harness. Implement:

int password_strength(const char *pw);

Return a score from 0 to 4, adding one point for each rule that passes:

  • +1 if the length is at least 8
  • +1 if the length is at least 12
  • +1 if the password uses at least 3 of the 4 character classes: lowercase, uppercase, digit, symbol
  • +1 if the password is NOT in the tiny banned set: password, 123456, qwerty, letmein

Deny by default: a NULL pointer scores 0 and must never be dereferenced. Every scan must stop at the terminating '\0' so you never read past the buffer.

Example

Given the identifier strong pointing at a 12-character password that mixes four classes and is not banned:

password_strength(strong) -> 4
password_strength(NULL)   -> 0

Input format

A single argument: pw, a pointer to a NUL-terminated C string, or NULL. The string lives in a fixed buffer owned by the harness.

Output format

An int in the range 0..4 — the number of strength rules the password satisfies.

Constraints

No dynamic allocation, no I/O, no global state. Must be memory-safe: NULL yields 0 with no dereference, and every character scan stops at the terminating '\0'. Banned-word checks must be exact full-string matches, not prefixes.

Starter code

int password_strength(const char *pw){
    /* TODO: implement the defensive strength score (0..4).
       This insecure stub always claims maximum strength and
       never bounds-checks or rejects NULL/banned input. */
    (void)pw;
    return 4;
}

Common mistakes

Dereferencing pw before the NULL check. Using strlen or strcmp on a NULL pointer. Treating a banned prefix as banned (matching "password" inside "password123"). Counting length with a signed int that could overflow, or reading past the '\0'. Requiring all 4 classes when the rule only needs 3. Off-by-one on the >=8 and >=12 boundaries.

Edge cases to handle

NULL pointer must return 0 without dereferencing. Empty string has length 0 and no classes but is not banned, so it scores 1. A password that merely starts with a banned word (e.g. "passwordX") is NOT banned — only exact full-string matches count. Boundary lengths 8 and 12 must each award their point. A symbol is anything outside the lower/upper/digit ranges.

Background lessons

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