From 08f1fcc6ac6a2f96cd2398fa9d5e33b2e7ebc6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Tue, 10 Feb 2026 22:07:26 +0100 Subject: [PATCH] fix: validate target and hostname inputs to prevent injection Add input validation to address security concerns: - Validate Target field in BuildRequest against safe character pattern (must be "all" or match alphanumeric/dash/underscore/dot pattern) - Filter hostnames discovered from nix flake show output, skipping any with invalid characters before using them in build commands This prevents potential command injection via crafted NATS messages or malicious flake configurations. Co-Authored-By: Claude Opus 4.5 --- internal/builder/builder.go | 15 +++++++++++++++ internal/messages/build.go | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/internal/builder/builder.go b/internal/builder/builder.go index 0ca481d..9894c3e 100644 --- a/internal/builder/builder.go +++ b/internal/builder/builder.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log/slog" + "regexp" "sort" "sync" "time" @@ -13,6 +14,10 @@ import ( "git.t-juice.club/torjus/homelab-deploy/internal/nats" ) +// hostnameRegex validates hostnames from flake output. +// Allows: alphanumeric, dashes, underscores, dots. +var hostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`) + // BuilderConfig holds the configuration for the builder. type BuilderConfig struct { NATSUrl string @@ -197,6 +202,16 @@ func (b *Builder) handleBuildRequest(subject string, data []byte) { } return } + // Filter out hostnames with invalid characters (security: prevent injection) + validHosts := make([]string, 0, len(hosts)) + for _, host := range hosts { + if hostnameRegex.MatchString(host) { + validHosts = append(validHosts, host) + } else { + b.logger.Warn("skipping hostname with invalid characters", "hostname", host) + } + } + hosts = validHosts // Sort hosts for consistent ordering sort.Strings(hosts) } else { diff --git a/internal/messages/build.go b/internal/messages/build.go index 2dbf43f..82749a2 100644 --- a/internal/messages/build.go +++ b/internal/messages/build.go @@ -45,6 +45,10 @@ func (r *BuildRequest) Validate() error { if r.Target == "" { return fmt.Errorf("target is required") } + // Target must be "all" or a valid hostname (same format as revision/branch) + if r.Target != "all" && !revisionRegex.MatchString(r.Target) { + return fmt.Errorf("invalid target format: %q", r.Target) + } if r.Branch != "" && !revisionRegex.MatchString(r.Branch) { return fmt.Errorf("invalid branch format: %q", r.Branch) }