validateGitSubDir ensures a subdirectory path is contained within the base directory and doesn't escape via path traversal. Unlike validatePathInBase for OCI artifacts, this allows nested directories but prevents traversal outside the base.
(base, subDir string)
| 138 | // and doesn't escape via path traversal. Unlike validatePathInBase for OCI artifacts, |
| 139 | // this allows nested directories but prevents traversal outside the base. |
| 140 | func validateGitSubDir(base, subDir string) error { |
| 141 | cleanSubDir := filepath.Clean(subDir) |
| 142 | |
| 143 | if filepath.IsAbs(cleanSubDir) { |
| 144 | return fmt.Errorf("git subdirectory must be relative, got: %s", subDir) |
| 145 | } |
| 146 | |
| 147 | if cleanSubDir == ".." || strings.HasPrefix(cleanSubDir, "../") || strings.HasPrefix(cleanSubDir, "..\\") { |
| 148 | return fmt.Errorf("git subdirectory path traversal detected: %s", subDir) |
| 149 | } |
| 150 | |
| 151 | if len(cleanSubDir) >= 2 && cleanSubDir[1] == ':' { |
| 152 | return fmt.Errorf("git subdirectory must be relative, got: %s", subDir) |
| 153 | } |
| 154 | |
| 155 | targetPath := filepath.Join(base, cleanSubDir) |
| 156 | cleanBase := filepath.Clean(base) |
| 157 | cleanTarget := filepath.Clean(targetPath) |
| 158 | |
| 159 | // Ensure the target starts with the base path |
| 160 | relPath, err := filepath.Rel(cleanBase, cleanTarget) |
| 161 | if err != nil { |
| 162 | return fmt.Errorf("invalid git subdirectory path: %w", err) |
| 163 | } |
| 164 | |
| 165 | if relPath == ".." || strings.HasPrefix(relPath, "../") || strings.HasPrefix(relPath, "..\\") { |
| 166 | return fmt.Errorf("git subdirectory escapes base directory: %s", subDir) |
| 167 | } |
| 168 | |
| 169 | return nil |
| 170 | } |
| 171 | |
| 172 | func (g gitRemoteLoader) resolveGitRef(ctx context.Context, path string, ref *gitutil.GitRef) error { |
| 173 | if !commitSHA.MatchString(ref.Ref) { |
no outgoing calls