mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
fix: properly validate GitHub repository URLs to prevent URL substring attacks
This commit is contained in:
parent
d4ca58d5d5
commit
b924e46d9f
2 changed files with 49 additions and 2 deletions
|
|
@ -915,12 +915,34 @@ describe("isGitHubRepository", () => {
|
|||
expect(isGitHubRepository("https://GITHUB.COM/user/repo.git")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true for GitHub subdomains", () => {
|
||||
expect(isGitHubRepository("https://gist.github.com/user/repo")).toBe(true)
|
||||
expect(isGitHubRepository("https://api.github.com/repos/user/repo")).toBe(true)
|
||||
expect(isGitHubRepository("git@gist.github.com:user/repo.git")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false for non-GitHub URLs", () => {
|
||||
expect(isGitHubRepository("https://gitlab.com/user/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("https://bitbucket.org/user/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("git@gitlab.com:user/repo.git")).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false for malicious URLs with github.com in hostname", () => {
|
||||
// Security: These URLs have "github.com" as part of the hostname but are not GitHub
|
||||
expect(isGitHubRepository("https://malicious-github.com/user/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("https://github.com.evil.com/user/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("https://fake-github.com/user/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("git@malicious-github.com:user/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("ssh://git@github.com.evil.com/user/repo.git")).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false for URLs with github.com in the path", () => {
|
||||
// Security: These URLs have "github.com" in the path but not as the hostname
|
||||
expect(isGitHubRepository("https://evil.com/github.com/malicious/repo.git")).toBe(false)
|
||||
expect(isGitHubRepository("https://attacker.com/fake/github.com/path")).toBe(false)
|
||||
expect(isGitHubRepository("git@evil.com:github.com/user/repo.git")).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false for undefined or empty URLs", () => {
|
||||
expect(isGitHubRepository(undefined)).toBe(false)
|
||||
expect(isGitHubRepository("")).toBe(false)
|
||||
|
|
|
|||
|
|
@ -222,8 +222,33 @@ export function isGitHubRepository(repositoryUrl?: string): boolean {
|
|||
}
|
||||
|
||||
try {
|
||||
// Check if the URL contains github.com
|
||||
return repositoryUrl.toLowerCase().includes("github.com")
|
||||
const url = repositoryUrl.toLowerCase().trim()
|
||||
|
||||
// Try to parse as HTTPS/HTTP URL
|
||||
if (url.startsWith("https://") || url.startsWith("http://")) {
|
||||
const parsed = new URL(url)
|
||||
return parsed.hostname === "github.com" || parsed.hostname.endsWith(".github.com")
|
||||
}
|
||||
|
||||
// Handle SSH format: git@github.com:user/repo.git
|
||||
if (url.startsWith("git@")) {
|
||||
const match = url.match(/^git@([^:]+):/)
|
||||
if (match && match[1]) {
|
||||
const host = match[1]
|
||||
return host === "github.com" || host.endsWith(".github.com")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle SSH with protocol: ssh://git@github.com/user/repo.git
|
||||
if (url.startsWith("ssh://")) {
|
||||
const match = url.match(/^ssh:\/\/(?:git@)?([^\/]+)/)
|
||||
if (match && match[1]) {
|
||||
const host = match[1]
|
||||
return host === "github.com" || host.endsWith(".github.com")
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue