Skip to content

fix(config): make schemeless credential masking linear - #979

Merged
acamarata merged 1 commit into
mainfrom
dw5-cli-5
Oct 27, 2026
Merged

acamarata merged 1 commit into
mainfrom
dw5-cli-5

Conversation

@acamarata

Copy link
Copy Markdown
Collaborator

Problem

TestMaskURLCredentialsLinear (internal/config/secretkeys_test.go) failed on main: schemeless unit "@a(": 4 KB 301µs, 40 KB 320ms: not linear. The schemeless masking added in #973 (D-0743) was quadratic on runs of @a(.

Cause

maskDSNUserinfo (internal/credmask/schemeless.go) sliced v[start:at] and ran IndexByte(':') over it for every @proto( match. When a match has no colon it is skipped without advancing done, so the token start never moved and each match rescanned the whole prefix: O(matches x length). The input is log lines and command output, so this is a DoS vector.

Fix

The existing forward pass now also records the token's first : and first :// (reset at token boundaries and after a mask), so each match is decided in O(1). Output is unchanged: a 2,000,000-case differential fuzz (old vs new maskDSNUserinfo, random mixes of @a(, :, ://, quotes, whitespace, =) found no difference (one-off, not committed).

Tests

  • New internal/credmask/linear_test.go: 9 adversarial shapes (@a(, :@a(, a:@, a:b@c(, x=y@a(, password=, long no-delimiter runs, ::::, @@@@) at 4 KB, 40 KB and 400 KB, best-of-7 timing, bound 50x + 2 ms per 10x step. Fails on old code ("@a(": 40000 B 3.6ms, 400000 B 258ms, 3/3 runs), passes on the fix.
  • schemelessTimeOf in the config test is now best-of-5 to cut flake.

Commands run

  • Old code, go test ./internal/config -run TestMaskURLCredentialsLinear -count=3 and -count=10: PASSED on my idle machine. The 4 KB / 40 KB check is load-sensitive, and the failure did not reproduce locally. The quadratic growth was reproduced directly: @a( took 0.19 ms at 4 KB, 4 ms at 40 KB and 292 ms at 400 KB.
  • New test against old schemeless.go: FAIL x3. Against the fix: PASS x3.
  • go vet ./internal/credmask ./internal/config: clean. gofmt -l: clean.
  • go test ./internal/config ./internal/credmask ./internal/reconcile -count=1: ok.
  • go test ./cmd/... -count=1: ok (cmd/commands 180s, cmd/nself).

Does not touch #958.

maskDSNUserinfo re-sliced and rescanned the whole token for a colon and
for :// on every @proto( match that was skipped, so a long run of '@A('
was quadratic. Track the token's first colon and first :// during the
existing forward pass instead.

Add an adversarial scaling test (best-of-N, 50x bound) and make the
config linearity helper best-of-N too.
@acamarata
acamarata merged commit c1d7e53 into main Oct 27, 2026
34 of 35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant