Skip to content

fix(read): sanitize unescaped C0 control chars before typed decode in getInto (#525) - #526

Open
xsvm wants to merge 1 commit into
civitai:mainfrom
xsvm:fix/escape-control-chars-in-get-into
Open

fix(read): sanitize unescaped C0 control chars before typed decode in getInto (#525)#526
xsvm wants to merge 1 commit into
civitai:mainfrom
xsvm:fix/escape-control-chars-in-get-into

Conversation

@xsvm

@xsvm xsvm commented Sep 6, 2026

Copy link
Copy Markdown

Closes #525

Context

PR #165 added escapeJSONStringControlChars in emitJSON to ensure --json output can always be parsed by jq. However, client.getInto() runs json.Unmarshal(raw, out) on the unescaped wire bytes before emitJSON is reached.

When an API response carries raw C0 control characters in string literals (e.g. literal \r inside a prompt), Go's strict encoding/json decoder fails immediately:

unexpected response from /api/v1/... (status 200)

and the command aborts before emitJSON is entered (as noted in internal/cmd/read_help.go:57).

Fix

  1. Moved escapeJSONStringControlChars down into pkg/civitai/read.go and exported it as EscapeJSONStringControlChars.
  2. In getInto, if !json.Valid(raw), attempt sanitization via EscapeJSONStringControlChars before attempting json.Unmarshal(raw, out).
  3. Replaced internal/cmd/read.go's escapeJSONStringControlChars with a one-line delegation to civitai.EscapeJSONStringControlChars.
  4. Added TestGetIntoSanitizesRawControlChars in pkg/civitai/read_test.go asserting a payload with a literal carriage return decodes cleanly.

Tests

  • TestGetIntoSanitizesRawControlChars (PASS)
  • TestEscapeJSONStringControlCharsLeavesStructuralWhitespace (PASS)
  • TestEmitJSONEscapesRawControlChars (PASS)
  • TestEmitJSONEscapesAllC0ControlChars (PASS)
  • TestEmitJSONValidInputUnchanged (PASS)
  • gofmt -s -l . clean, go vet clean.

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.

Raw C0 control characters in API responses fail in getInto before emitJSON gets called

1 participant