From e89a0043e7a5cb4abd7d60182d9dc591153b5f6a Mon Sep 17 00:00:00 2001 From: 0xv1n Date: Thu, 16 Jul 2026 22:59:42 -0700 Subject: [PATCH] add simple env guardrail --- src/web/backend/settings/handlers.go | 4 ++++ src/web/backend/settings/settings.go | 25 ++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/web/backend/settings/handlers.go b/src/web/backend/settings/handlers.go index f7c3627..9294b32 100644 --- a/src/web/backend/settings/handlers.go +++ b/src/web/backend/settings/handlers.go @@ -68,6 +68,10 @@ func (s *Settings) HandleSaveConfig(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } + if err := validateEnvText(string(data)); err != nil { + http.Error(w, "invalid .env content: "+err.Error(), http.StatusBadRequest) + return + } if err := os.WriteFile(s.cfg.WebEnvPath, data, 0600); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/web/backend/settings/settings.go b/src/web/backend/settings/settings.go index cebf45a..4159d75 100644 --- a/src/web/backend/settings/settings.go +++ b/src/web/backend/settings/settings.go @@ -1,9 +1,9 @@ package settings import ( - "strings" - "os" "fmt" + "os" + "strings" "explo/src/web/backend/app" ) @@ -21,6 +21,7 @@ type Settings struct { func NewSettings(Config app.Config) *Settings { return &Settings{cfg: Config} } + // parseEnvText parses key=value lines, ignoring comments, blanks and unquotes variables func (s *Settings) ParseEnvText(text string) map[string]string { out := map[string]string{} @@ -49,6 +50,24 @@ func (s *Settings) ParseEnvText(text string) map[string]string { return out } +// validateEnvText rejects content that isn't valid .env syntax before it's written to +// disk. cleanenv.ReadConfig fails hard on any non-blank, non-comment line without a "=", +// which causes a crash loop for the container with no way tofix since the UI becomes +// inaccessible.Mirrors ParseEnvText's line rules,but treats a missing "=" as an error +// instead of silently skipping the line. +func validateEnvText(text string) error { + for i, line := range strings.Split(text, "\n") { + t := strings.TrimSpace(line) + if t == "" || strings.HasPrefix(t, "#") { + continue + } + if !strings.Contains(t, "=") { + return fmt.Errorf("line %d is not valid .env syntax (expected KEY=value): %q", i+1, t) + } + } + return nil +} + // updateEnvKeys reads the env file (falling back to fallback if missing), updates the // given key=value pairs in-place preserving comments, and writes the result back. func (s *Settings) UpdateEnvKeys(updates map[string]string, fallback []byte) error { @@ -119,4 +138,4 @@ func formatEnvValue(v string) string { } return v -} \ No newline at end of file +}