Great work!

XP to next level

BugEater

Case-Sensitivity Security Risks

Case sensitivity is not merely a data integrity issue — in several well-defined scenarios, it becomes a security boundary. Getting it wrong has concrete security consequences.

Token and Secret Comparison

Never use case-insensitive comparison for secrets.

Password reset tokens, email verification codes, session tokens, API keys — any value that serves as a credential must be compared with exact byte equality. A case-insensitive comparison of tokens effectively doubles the valid token space for an attacker attempting brute force.

A 32-character hex token with case-insensitive comparison reduces the effective entropy: a1b2c3... would match A1B2C3..., a1B2c3..., and all other case variants. For alphanumeric tokens using A-F (hex), this is not a large reduction. For base64 tokens using A-Z and a-z, a case-insensitive comparison makes every character have 26 effective variants instead of 52, halving the bit-security of each character position.

The correct implementation: compare tokens byte-by-byte with a constant-time comparison function. Never toLowerCase() tokens before comparison.

Permission Bypass via Case Manipulation

A permission check that compares role names case-sensitively but stores them inconsistently is a bypass vector:

// Check is case-sensitive
if (user.getRole().equals("ADMIN")) { return grantAccess(); }

// But the database sometimes stores "admin" (lowercase)
// → user with role "admin" fails the permission check
// → user with role "ADMIN" passes

In this case, the inconsistency is a denial-of-service: legitimate admins can't access admin features. But the inverse is more dangerous:

// Check is case-insensitive
if (user.getRole().equalsIgnoreCase("user")) { return restrictAccess(); }

// If a role "User" is created that the check doesn't match...
// The admin panel might have a different check
if (user.getRole().equals("User")) { return grantAdminAccess(); }

Real-world bypasses often exploit the gap between how roles are stored, how they are compared at the restriction layer, and how they are compared at the permission-grant layer.

Username Enumeration via Case

If the login endpoint and the "forgot password" endpoint handle case differently, an attacker can enumerate registered usernames:

  1. Submit Admin to the login endpoint → "Invalid credentials"
  2. Submit Admin to the forgot password endpoint → "Email sent" (because forgot-password uses case-insensitive lookup and finds admin)

This confirms Admin/admin is a registered user without needing a password. The login endpoint revealed nothing; the forgot-password endpoint revealed the account's existence via its case-insensitive lookup.

The fix: use the same case normalization policy across all endpoints that process the same field.

The Unicode Case Normalization Attack

Some applications normalize input by calling toUpperCase() or toLowerCase() before comparison. In Turkish locale, this introduces a subtle vulnerability:

  • Input: ı (U+0131, Turkish dotless i, lowercase)
  • After toUpperCase() in Turkish locale: I (U+0049, ASCII uppercase I)
  • After toUpperCase() in English locale: I (U+0049, same result)

But the reverse:

  • Input: i (U+0069, Latin small letter i)
  • After toUpperCase() in Turkish locale: İ (U+0130, dotted capital I)
  • After toUpperCase() in English locale: I (U+0049)

This means: the same input i produces different uppercase values depending on the server's locale. An application that registers users with case normalization in one locale and validates in another may accept or reject inputs that should behave symmetrically.

This is a real attack vector when applications are deployed in Turkish-locale environments.

Testing for Case Security Issues

For each authentication or authorization flow:

  1. Register/create with one case (e.g., Admin)
  2. Attempt authentication with different cases (ADMIN, admin, aDmIn)
  3. Note which cases succeed and which fail
  4. Repeat the same cases on every other endpoint that accepts the same field
  5. Verify consistency — not just "does each work" but "are the results consistent across paths?"

For tokens specifically:

  1. Capture a valid token
  2. Submit the token with one character changed in case
  3. The modified token must be rejected — if it is accepted, the comparison is case-insensitive (a security defect)

Quiz

An application normalises usernames to lowercase at registration but uses a case-sensitive comparison at login. A user registered as alice cannot log in. What is the most likely cause?

A security researcher registers as Admin (capital A) and gains access to admin dashboards. What class of vulnerability is this?

A user sets the password Secret1! with a capital S. They later try secret1! (lowercase s). What should happen?

A penetration tester finds that /admin returns 403 but /Admin returns 200 with the admin panel. What class of vulnerability is this?