check / check (pull_request) Successful in 1m22s
Objects fetched from the store are untrusted; several decode paths let one expand or print without limit. - blobgen.LimitReader errors past a byte cap (not io.LimitReader's silent EOF). DecodeManifest reads through caps on both compressed input and decompressed output, far above any real manifest, so json.Decode cannot buffer a compressible bomb. FetchAndDecryptBlob bounds decompression to the blob's recorded uncompressed_size (not the restoring host's blob_size_limit). - downloadSnapshotDB streams straight from storage to its temp file with io.Copy, replacing two ReadAll calls that held the whole database twice. - FetchBlob drops the per-blob Stat round-trip, its expectedSize parameter and returned size, all of which only fed a debug log. - TTYHandler and ui.Writer escape control characters in messages, attribute keys/values, and rendered identifiers/paths before colour codes are applied, so a crafted value cannot drive the terminal. Model: opus-4-8
40 lines
1.3 KiB
Go
40 lines
1.3 KiB
Go
package log_test
|
|
|
|
import (
|
|
"bytes"
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/vaultik/internal/log"
|
|
)
|
|
|
|
// TestTTYHandlerEscapesControlCharacters logs a message and an attribute
|
|
// value that each carry an ESC and a newline — the shape a crafted path or
|
|
// storage error from the destination would take — and checks neither raw
|
|
// byte reaches the output. The handler's own colour codes (ESC ... m) are
|
|
// stripped first; any ESC left after that came from the untrusted value.
|
|
func TestTTYHandlerEscapesControlCharacters(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var buf bytes.Buffer
|
|
|
|
logger := slog.New(log.NewTTYHandler(&buf, debugHandlerOptions()))
|
|
logger.Info("start\x1b[31mZAP\nend", "target", "a\x1b[31mZAP\nb")
|
|
|
|
out := buf.String()
|
|
|
|
// The only newline is the line terminator; the injected ones were escaped.
|
|
require.Equal(t, 1, strings.Count(out, "\n"),
|
|
"a newline in the message or a value must be escaped, not emitted raw")
|
|
|
|
// After the handler's own colour codes are removed, no ESC survives.
|
|
stripped := ansiEscape.ReplaceAllString(out, "")
|
|
require.NotContains(t, stripped, "\x1b",
|
|
"a raw ESC from the message or a value must not reach the terminal")
|
|
|
|
// The escaped form is what appears instead.
|
|
require.Contains(t, out, `\x1b`)
|
|
}
|