Skip to content

Commit 4abc6ae

Browse files
authored
Merge pull request #110 from deeploy-sh/hotfix/security-issues
Hotfix/security issues
2 parents ee180fc + 7b7f3b5 commit 4abc6ae

6 files changed

Lines changed: 53 additions & 11 deletions

File tree

internal/server/auth/cli_session.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func SetSessionToken(sessionID, token string) {
4040
sessionsMu.Lock()
4141
defer sessionsMu.Unlock()
4242

43-
log.Printf("[CLI Auth] SetSessionToken: session=%s token=%s...", sessionID, token[:min(10, len(token))])
43+
log.Printf("[CLI Auth] SetSessionToken: session=%s", sessionID)
4444

4545
session, exists := sessions[sessionID]
4646
if !exists {

internal/server/config/config.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func Load() *Config {
3131
// Always require secrets (generated by install script)
3232
jwtSecret := requireEnv("JWT_SECRET", "min 32 characters")
3333
encryptionKey := requireEnv("ENCRYPTION_KEY", "exactly 32 characters")
34+
cookieSecure := getEnvBool("COOKIE_SECURE", appEnv == "production")
3435

3536
return &Config{
3637
AppEnv: appEnv,
@@ -39,7 +40,7 @@ func Load() *Config {
3940
DBConnection: dbConnection,
4041
JWTSecret: jwtSecret,
4142
EncryptionKey: encryptionKey,
42-
CookieSecure: false, // HTTP allowed, Traefik enforces HTTPS when domain configured
43+
CookieSecure: cookieSecure,
4344
BuildDir: getEnv("BUILD_DIR", "/tmp/deeploy-builds"),
4445
TraefikConfigDir: getEnv("TRAEFIK_CONFIG_DIR", "/traefik/dynamic"),
4546
}
@@ -61,6 +62,20 @@ func getEnv(key, fallback string) string {
6162
return value
6263
}
6364

65+
func getEnvBool(key string, fallback bool) bool {
66+
value, exists := os.LookupEnv(key)
67+
if !exists || value == "" {
68+
return fallback
69+
}
70+
if value == "1" || value == "true" || value == "TRUE" || value == "True" {
71+
return true
72+
}
73+
if value == "0" || value == "false" || value == "FALSE" || value == "False" {
74+
return false
75+
}
76+
return fallback
77+
}
78+
6479
func requireEnv(key, hint string) string {
6580
value := os.Getenv(key)
6681
if value == "" {

internal/server/cookie/cookie.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import (
44
"net/http"
55
)
66

7-
func SetCookie(w http.ResponseWriter, token string) {
7+
func SetCookie(w http.ResponseWriter, token string, secure bool) {
88
http.SetCookie(w, &http.Cookie{
99
Name: "token",
1010
Value: token,
1111
Path: "/",
1212
HttpOnly: true,
13-
Secure: false, // HTTP allowed, Traefik enforces HTTPS when domain configured
13+
Secure: secure,
1414
SameSite: http.SameSiteStrictMode,
1515
MaxAge: 3600 * 24,
1616
})

internal/server/docker/docker.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ import (
2727

2828
// ansiRegex matches ANSI escape codes (colors, formatting)
2929
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`)
30+
var gitURLCredentialsRegex = regexp.MustCompile(`(https?://)[^@\s/]+@`)
31+
32+
var tokenPatterns = []*regexp.Regexp{
33+
regexp.MustCompile(`ghp_[A-Za-z0-9_]+`),
34+
regexp.MustCompile(`github_pat_[A-Za-z0-9_]+`),
35+
regexp.MustCompile(`glpat-[A-Za-z0-9_-]+`),
36+
regexp.MustCompile(`ATBB[A-Za-z0-9_-]+`),
37+
}
3038

3139
// NetworkName is the shared network where Traefik lives.
3240
// New containers join this network so Traefik can route traffic to them.
@@ -85,12 +93,27 @@ func (d *DockerService) CloneRepo(repoURL, branch, token string) (string, error)
8593
output, err := cmd.CombinedOutput()
8694
if err != nil {
8795
os.RemoveAll(cloneDir) // Cleanup failed clone attempt
88-
return "", fmt.Errorf("git clone failed: %s - %w", string(output), err)
96+
safeOutput := sanitizeGitOutput(string(output), token)
97+
if strings.TrimSpace(safeOutput) == "" {
98+
return "", fmt.Errorf("git clone failed: %w", err)
99+
}
100+
return "", fmt.Errorf("git clone failed: %s - %w", safeOutput, err)
89101
}
90102

91103
return cloneDir, nil
92104
}
93105

106+
func sanitizeGitOutput(output, token string) string {
107+
sanitized := gitURLCredentialsRegex.ReplaceAllString(output, "${1}***@")
108+
if token != "" {
109+
sanitized = strings.ReplaceAll(sanitized, token, "***")
110+
}
111+
for _, pattern := range tokenPatterns {
112+
sanitized = pattern.ReplaceAllString(sanitized, "***")
113+
}
114+
return sanitized
115+
}
116+
94117
// BuildImage builds a Docker image from a directory with a Dockerfile.
95118
// logCallback is called for each line of build output (can be nil).
96119
func (d *DockerService) BuildImage(ctx context.Context, buildPath, dockerfilePath, imageName string, logCallback func(string)) (string, error) {

internal/server/handler/user.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ import (
1414
)
1515

1616
type UserHandler struct {
17-
service service.UserServiceInterface
17+
service service.UserServiceInterface
18+
cookieSecure bool
1819
}
1920

20-
func NewUserHandler(service *service.UserService) *UserHandler {
21-
return &UserHandler{service: service}
21+
func NewUserHandler(service *service.UserService, cookieSecure bool) *UserHandler {
22+
return &UserHandler{
23+
service: service,
24+
cookieSecure: cookieSecure,
25+
}
2226
}
2327

2428
func (h *UserHandler) LandingView(w http.ResponseWriter, r *http.Request) {
@@ -71,7 +75,7 @@ func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) {
7175
return
7276
}
7377

74-
cookie.SetCookie(w, token)
78+
cookie.SetCookie(w, token, h.cookieSecure)
7579
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
7680
}
7781

@@ -117,7 +121,7 @@ func (h *UserHandler) Register(w http.ResponseWriter, r *http.Request) {
117121
return
118122
}
119123

120-
cookie.SetCookie(w, token)
124+
cookie.SetCookie(w, token, h.cookieSecure)
121125
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
122126
}
123127

internal/server/routes/routes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func Setup(app *app.App) http.Handler {
1717

1818
// Handlers
1919
auth := mw.NewAuthMiddleware(app.UserService)
20-
userHandler := handlers.NewUserHandler(app.UserService)
20+
userHandler := handlers.NewUserHandler(app.UserService, app.Cfg.CookieSecure)
2121
projectHandler := handlers.NewProjectHandler(app.ProjectService, app.PodService)
2222
podHandler := handlers.NewPodHandler(app.PodService)
2323
gitTokenHandler := handlers.NewGitTokenHandler(app.GitTokenService)

0 commit comments

Comments
 (0)