Improve Git dumb HTTP security (#780)
Go CI / Test (sqlite, 1.26, ubuntu-latest) (push) Has been cancelled
Go CI / Build (1.26, macOS-latest) (push) Has been cancelled
Go CI / Build (1.26, ubuntu-latest) (push) Has been cancelled
Go CI / Build (1.26, windows-latest) (push) Has been cancelled
Go CI / Lint (push) Has been cancelled
Go CI / Check (push) Has been cancelled
Go CI / Test (mysql, 1.26, mysql:8, ubuntu-latest, 3306:3306) (push) Has been cancelled
Go CI / Test (postgres, 1.26, postgres:16, ubuntu-latest, 5432:5432) (push) Has been cancelled
Go CI / Test (sqlite, 1.26, macOS-latest) (push) Has been cancelled

This commit is contained in:
Thomas
2026-07-30 10:21:32 +02:00
committed by GitHub
parent 0e14994532
commit a7b4f6df31
+21 -3
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"path" "path/filepath"
"strings" "strings"
"time" "time"
@@ -37,8 +37,13 @@ func idxFile(ctx *context.Context) error {
} }
func sendFile(ctx *context.Context, contentType string) error { func sendFile(ctx *context.Context, contentType string) error {
gitFile := "/" + strings.Join(strings.Split(ctx.Request().URL.Path, "/")[3:], "/") repoPath := ctx.GetData("repositoryPath").(string)
gitFile = path.Join(ctx.GetData("repositoryPath").(string), gitFile) relPath := strings.Join(strings.Split(ctx.Request().URL.Path, "/")[3:], "/")
gitFile, err := containedPath(repoPath, relPath)
if err != nil {
return ctx.ErrorRes(404, "File not found", nil)
}
fi, err := os.Stat(gitFile) fi, err := os.Stat(gitFile)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return ctx.ErrorRes(404, "File not found", nil) return ctx.ErrorRes(404, "File not found", nil)
@@ -49,6 +54,19 @@ func sendFile(ctx *context.Context, contentType string) error {
return ctx.File(gitFile) return ctx.File(gitFile)
} }
func containedPath(baseDir, relPath string) (string, error) {
base := filepath.Clean(baseDir)
joined := filepath.Clean(filepath.Join(base, relPath))
if joined == base {
return "", fmt.Errorf("path %q resolves to the repository root", relPath)
}
if !strings.HasPrefix(joined, base+string(os.PathSeparator)) {
return "", fmt.Errorf("path %q escapes repository %q", relPath, base)
}
return joined, nil
}
func noCacheHeaders(ctx *context.Context) { func noCacheHeaders(ctx *context.Context) {
ctx.Response().Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 UTC") ctx.Response().Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 UTC")
ctx.Response().Header().Set("Pragma", "no-cache") ctx.Response().Header().Set("Pragma", "no-cache")