From 47d4b3b6e4d68660e6e1e05fe2e1c0839f86e40e Mon Sep 17 00:00:00 2001 From: bndw Date: Tue, 10 Feb 2026 21:29:08 -0800 Subject: Harden security: name validation, scoped sudoers, safe.directory - Add ValidateName() enforcing ^[a-z][a-z0-9-]{0,62}$ on all entry points - Tighten sudoers to restrict cp sources/destinations and chown targets - Scope git safe.directory to www-data user only (preserves CVE-2022-24765) - Add www-data to git group and caddy to www-data group for fcgiwrap - Fix vanity import template to use orig_uri placeholder - Restart (not reload) services after group changes - Add name validation to env subcommands and deploy_cmd --- internal/state/state.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'internal') diff --git a/internal/state/state.go b/internal/state/state.go index 324fd34..c9aa21d 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "regexp" ) // State represents the entire local deployment state @@ -27,6 +28,7 @@ type App struct { Domain string `json:"domain"` Port int `json:"port,omitempty"` // only for type="app" or "git-app" Repo string `json:"repo,omitempty"` // only for git types, e.g. "/srv/git/foo.git" + Public bool `json:"public,omitempty"` // only for git types, enables HTTP clone access Env map[string]string `json:"env,omitempty"` // only for type="app" or "git-app" Args string `json:"args,omitempty"` // only for type="app" Files []string `json:"files,omitempty"` // only for type="app" @@ -38,6 +40,17 @@ const ( startPort = 8001 ) +var validName = regexp.MustCompile(`^[a-z][a-z0-9-]{0,62}$`) + +// ValidateName checks that a name is safe for use in shell commands, +// file paths, systemd units, and DNS labels. +func ValidateName(name string) error { + if !validName.MatchString(name) { + return fmt.Errorf("invalid name %q: must start with a lowercase letter, contain only lowercase letters, digits, and hyphens, and be 1-63 characters", name) + } + return nil +} + // Load reads state from ~/.config/ship/state.json func Load() (*State, error) { path := statePath() -- cgit v1.2.3