@@ -39,6 +39,32 @@ const (
3939 OciPrefix = "oci://"
4040)
4141
42+ // validatePathInBase ensures a file path is contained within the base directory,
43+ // as OCI artifacts resources must all live within the same folder.
44+ func validatePathInBase (base , unsafePath string ) error {
45+ // Reject paths with path separators regardless of OS
46+ if strings .ContainsAny (unsafePath , "\\ /" ) {
47+ return fmt .Errorf ("invalid OCI artifact" )
48+ }
49+
50+ // Join the base with the untrusted path
51+ targetPath := filepath .Join (base , unsafePath )
52+
53+ // Get the directory of the target path
54+ targetDir := filepath .Dir (targetPath )
55+
56+ // Clean both paths to resolve any .. or . components
57+ cleanBase := filepath .Clean (base )
58+ cleanTargetDir := filepath .Clean (targetDir )
59+
60+ // Check if the target directory is the same as base directory
61+ if cleanTargetDir != cleanBase {
62+ return fmt .Errorf ("invalid OCI artifact" )
63+ }
64+
65+ return nil
66+ }
67+
4268func ociRemoteLoaderEnabled () (bool , error ) {
4369 if v := os .Getenv (OCI_REMOTE_ENABLED ); v != "" {
4470 enabled , err := strconv .ParseBool (v )
@@ -158,12 +184,6 @@ func (g ociRemoteLoader) pullComposeFiles(ctx context.Context, local string, man
158184 if err != nil {
159185 return err
160186 }
161- composeFile := filepath .Join (local , "compose.yaml" )
162- f , err := os .Create (composeFile )
163- if err != nil {
164- return err
165- }
166- defer f .Close () //nolint:errcheck
167187 if (manifest .ArtifactType != "" && manifest .ArtifactType != oci .ComposeProjectArtifactType ) ||
168188 (manifest .ArtifactType == "" && manifest .Config .MediaType != oci .ComposeEmptyConfigMediaType ) {
169189 return fmt .Errorf ("%s is not a compose project OCI artifact, but %s" , ref .String (), manifest .ArtifactType )
@@ -182,15 +202,7 @@ func (g ociRemoteLoader) pullComposeFiles(ctx context.Context, local string, man
182202
183203 switch layer .MediaType {
184204 case oci .ComposeYAMLMediaType :
185- target := f
186- _ , extends := layer .Annotations ["com.docker.compose.extends" ]
187- if extends {
188- target , err = os .Create (filepath .Join (local , layer .Annotations ["com.docker.compose.file" ]))
189- if err != nil {
190- return err
191- }
192- }
193- if err := writeComposeFile (layer , i , target , content ); err != nil {
205+ if err := writeComposeFile (layer , i , local , content ); err != nil {
194206 return err
195207 }
196208 case oci .ComposeEnvFileMediaType :
@@ -203,14 +215,25 @@ func (g ociRemoteLoader) pullComposeFiles(ctx context.Context, local string, man
203215 return nil
204216}
205217
206- func writeComposeFile (layer spec.Descriptor , i int , f * os.File , content []byte ) error {
218+ func writeComposeFile (layer spec.Descriptor , i int , local string , content []byte ) error {
219+ file := "compose.yaml"
220+ if extends , ok := layer .Annotations ["com.docker.compose.extends" ]; ok {
221+ if err := validatePathInBase (local , extends ); err != nil {
222+ return err
223+ }
224+ }
225+ f , err := os .Create (filepath .Join (local , file ))
226+ if err != nil {
227+ return err
228+ }
229+ defer func () { _ = f .Close () }()
207230 if _ , ok := layer .Annotations ["com.docker.compose.file" ]; i > 0 && ok {
208231 _ , err := f .Write ([]byte ("\n ---\n " ))
209232 if err != nil {
210233 return err
211234 }
212235 }
213- _ , err : = f .Write (content )
236+ _ , err = f .Write (content )
214237 return err
215238}
216239
@@ -219,15 +242,16 @@ func writeEnvFile(layer spec.Descriptor, local string, content []byte) error {
219242 if ! ok {
220243 return fmt .Errorf ("missing annotation com.docker.compose.envfile in layer %q" , layer .Digest )
221244 }
222- otherFile , err := os .Create (filepath .Join (local , envfilePath ))
223- if err != nil {
245+ if err := validatePathInBase (local , envfilePath ); err != nil {
224246 return err
225247 }
226- _ , err = otherFile . Write ( content )
248+ otherFile , err := os . Create ( filepath . Join ( local , envfilePath ) )
227249 if err != nil {
228250 return err
229251 }
230- return nil
252+ defer func () { _ = otherFile .Close () }()
253+ _ , err = otherFile .Write (content )
254+ return err
231255}
232256
233257var _ loader.ResourceLoader = ociRemoteLoader {}
0 commit comments