Mask camelCase secret names and URL userinfo credentials

AB
3d ago
+57-9

Problem

Two gaps in redaction, both of which end up in stored request records and surfaced errors unless the value also happens to be a resolved secret.

  1. The SECRETISH_* patterns in src/redaction.ts and src/http-executor.ts only match a keyword like token or secret at the start of the name or after - or _, so camelCase names slip through.

    redactUrl("https://api.example.com/v1/x?accessToken=t1&clientSecret=s2&authToken=a3&apiKey=k4", []);
    

    Observed: the URL comes back unchanged, all four values visible. Expected: all four values masked.

  2. Credentials in URL userinfo are never removed.

    redactUrl("https://admin:hunter2@api.example.com/v1/x", []);
    redactMessage("failed https://admin:hunter2@api.example.com/x", []);
    

    Observed: both return admin:hunter2@ intact. Expected: the credentials are blanked.

Fix

  • New isSecretishName(name, pattern) in redaction.ts tests the name as is and again with camelCase boundaries split (accessToken is tested as access_Token). All lowercase names are unaffected, so monkey, monkeyId and authorId still pass through.
  • Used for query redaction in redactUrl, for the sensitive header and query checks in executeCall, for response header redaction, and for the fuzz body secret collection.
  • redactUrl and redactMessage now blank url.username and url.password.
  • Probe credential matching (isProbeCredentialHeader, isProbeCredentialQuery) is unchanged, so what noAuth and invalidAuth mutate is the same as before. Body key redaction for call is also unchanged.

Tests

Added cases to src/redaction.test.ts: camelCase query names are masked, benign camelCase names (monkeyId, authorId) are kept, and userinfo is stripped by both redactUrl and redactMessage. The three new masking tests fail on main and pass with the fix.

  • pnpm test: 259 passed, 2 skipped
  • pnpm typecheck: clean
  • pnpm lint: clean

Worth knowing

  • A few more camelCase names get masked in evidence (sessionId, for example). session_id was already masked, so this is consistent.
  • The username is blanked along with the password. Keeping the user and masking only the password is a one line change if you prefer that.
  • Probe matching still misses camelCase names, so a noAuth probe may still send an accessToken query param. Left out to keep this to redaction; happy to follow up separately.