Skip to content

Code review batch 2: credential redaction, redirect/setup hardening, integration build tag#151

Merged
yorkable merged 3 commits into
mainfrom
harden-creds-and-tests
Jun 11, 2026
Merged

Code review batch 2: credential redaction, redirect/setup hardening, integration build tag#151
yorkable merged 3 commits into
mainfrom
harden-creds-and-tests

Conversation

@yorkable

Copy link
Copy Markdown
Contributor

Second implementation batch from the code review — credential-safety, test-safety, and setup-server hardening. 5 issues, three commits, all covered by new unit tests and verified end-to-end where noted. go build, go vet, and go test -race are green.

Credential safety

  • --debug prints request bodies, leaking service auth secrets #124--debug now redacts sensitive keys (auth_values, password, token, *secret, hmac, …) in request bodies and form fields. The masked API-key header had given a false sense that --debug output was safe to share; service credentials no longer print in cleartext. Verified end-to-end: the body prints "auth_values":"***REDACTED***" and the real secret never appears.
  • API-key header survives cross-host redirect; http base URLs allowed #125 — the HTTP client drops the Syllable-API-Key header on a cross-host redirect (Go's default policy only strips standard auth headers, not custom ones), and warns when a non-loopback base URL uses plaintext http. All http.Client instances share this policy via newHTTPClient.

Setup-server hardening

  • setup config server has no CSRF/Origin/Host defense #123 — the browser-based syllable setup server's /save endpoint authenticated nothing, so a page open in the user's browser could POST a poisoned config and exfiltrate the key on the next command. It now requires a per-session CSRF token (returned as X-Syllable-CSRF), a loopback Host, and a matching Origin. Verified end-to-end with an isolated HOME: no-token / cross-origin / rebound-Host requests are rejected 403; the legitimate flow still saves.
  • setup: double "Save & Exit" panics (close of closed channel) #129 — double "Save & Exit" panicked the process (close of a closed channel); fixed with sync.Once, and /save is now serialized with a mutex so concurrent submits can't race on the shared config.

Test safety

New unit tests: body/field redaction, cross-host redirect stripping, insecure-URL warning, the setup CSRF guard, token generation, and page-token injection.

Closes #123, #124, #125, #129, #134.

🤖 Generated with Claude Code

yorkable and others added 3 commits June 11, 2026 11:06
…d redirects from leaking credentials

Continues the code-review fixes (#124, #125, #134).

#134 — the live integration suite now requires the `integration` build tag in
addition to an auth env var, so `go test ./...` (including the GoReleaser
pre-release hook) can no longer fire live CRUD when SYLLABLE_API_KEY happens to
be set. spec-live-check.yml runs it with -tags integration; CONTRIBUTING updated.

#124 — `--debug` now redacts sensitive keys (auth_values, password, token,
*secret, hmac, …) in request bodies and form fields. The masked API-key header
gave a false sense that --debug output was safe to paste; service credentials
no longer print in cleartext.

#125 — the client drops the Syllable-API-Key header on a cross-host redirect
(Go's default policy only strips standard auth headers, not custom ones) and
warns when a non-loopback base URL uses plaintext http. All http.Client
instances share this redirect policy via newHTTPClient.

New unit tests cover redaction, cross-host redirect stripping, and the
insecure-URL warning; verified end-to-end that --debug prints
"auth_values":"***REDACTED***". go build/vet/test -race green.

Co-Authored-By: Claude Fable 5 <[email protected]>
…gin checks (#123)

The browser-based `syllable setup` server bound to loopback but its /save
handler authenticated nothing, so a malicious page open in the user's browser
could POST a poisoned config (e.g. a base_url pointing at an attacker) and
exfiltrate the API key on the next command.

/save now requires:
- a per-session random CSRF token (crypto/rand) embedded in the served page and
  returned as X-Syllable-CSRF — a cross-origin page can't read it, and the
  custom header forces a CORS preflight the server never approves;
- a loopback Host header (defeats DNS rebinding);
- a matching Origin when the browser supplies one.

Verified end-to-end with an isolated HOME: requests with no token, a
cross-origin Origin, or a rebound Host are rejected 403, while the legitimate
same-origin flow still saves. New unit tests cover the guard, token generation,
and page injection. go build/vet/test -race green.

Co-Authored-By: Claude Fable 5 <[email protected]>
…#129)

A second "Save & Exit" (double-click or browser retry) spawned a second
goroutine that closed the already-closed `done` channel, panicking the process.
Guard the close with sync.Once, and serialize the /save handler with a mutex so
concurrent submits can't race on the shared real/masked config.

go build/vet/test -race green.

Co-Authored-By: Claude Fable 5 <[email protected]>
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.

setup config server has no CSRF/Origin/Host defense

1 participant