From 214b5f83ba1e1a6ec1c14d0abbb635d95a040544 Mon Sep 17 00:00:00 2001 From: clawbot Date: Thu, 19 Feb 2026 20:17:25 -0800 Subject: [PATCH] fix: restrict SCP-like URLs to git user only and reject path traversal - Changed SCP regex to only accept 'git' as the username - Added path traversal check: reject URLs containing '..' - Added test cases for non-git users and path traversal --- internal/handlers/repo_url_validation.go | 8 +++++++- internal/handlers/repo_url_validation_test.go | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/handlers/repo_url_validation.go b/internal/handlers/repo_url_validation.go index 30384b3..0598a93 100644 --- a/internal/handlers/repo_url_validation.go +++ b/internal/handlers/repo_url_validation.go @@ -17,7 +17,8 @@ var ( ) // scpLikeRepoRe matches SCP-like git URLs: git@host:path (e.g. git@github.com:user/repo.git). -var scpLikeRepoRe = regexp.MustCompile(`^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+:.+$`) +// Only the "git" user is allowed, as that is the standard for SSH deploy keys. +var scpLikeRepoRe = regexp.MustCompile(`^git@[a-zA-Z0-9._-]+:.+$`) // validateRepoURL checks that the given repository URL is valid and uses an allowed scheme. func validateRepoURL(repoURL string) error { @@ -25,6 +26,11 @@ func validateRepoURL(repoURL string) error { return errRepoURLEmpty } + // Reject path traversal in any URL format + if strings.Contains(repoURL, "..") { + return errRepoURLInvalid + } + // Check for SCP-like git URLs first (git@host:path) if scpLikeRepoRe.MatchString(repoURL) { return nil diff --git a/internal/handlers/repo_url_validation_test.go b/internal/handlers/repo_url_validation_test.go index e997da0..be7416a 100644 --- a/internal/handlers/repo_url_validation_test.go +++ b/internal/handlers/repo_url_validation_test.go @@ -32,6 +32,11 @@ func TestValidateRepoURL(t *testing.T) { {name: "no host https", url: "https:///path", wantErr: true}, {name: "no path https", url: "https://github.com", wantErr: true}, {name: "no path https trailing slash", url: "https://github.com/", wantErr: true}, + {name: "SCP-like non-git user", url: "root@github.com:user/repo.git", wantErr: true}, + {name: "SCP-like arbitrary user", url: "admin@github.com:user/repo.git", wantErr: true}, + {name: "path traversal SCP", url: "git@github.com:../../etc/passwd", wantErr: true}, + {name: "path traversal https", url: "https://github.com/user/../../../etc/passwd", wantErr: true}, + {name: "path traversal in middle", url: "https://github.com/user/repo/../secret", wantErr: true}, } for _, tc := range tests {