diff --git a/benchmarks/util.go b/benchmarks/util.go
index aa0e93673..968dd2f66 100644
--- a/benchmarks/util.go
+++ b/benchmarks/util.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/opencontainers/go-digest"
+	"github.com/pkg/errors"
 	"github.com/stackrox/scanner/pkg/clairify/types"
 	server "github.com/stackrox/scanner/pkg/scan"
 	"github.com/stretchr/testify/require"
@@ -41,7 +42,11 @@ func MustGetLayerReadClosers(b *testing.B, imageName string) []*layerReadCloser
 func getLayerDownloadReadCloser(reg types.Registry, image *types.Image, layerName string) *server.LayerDownloadReadCloser {
 	return &server.LayerDownloadReadCloser{
 		Downloader: func() (io.ReadCloser, error) {
-			return reg.DownloadLayer(image.Remote, digest.Digest(layerName))
+			dig, err := digest.Parse(layerName)
+			if err != nil {
+				return nil, errors.Wrapf(err, "invalid layer digest %q", layerName)
+			}
+			return reg.DownloadLayer(image.Remote, dig)
 		},
 	}
 }
diff --git a/go.mod b/go.mod
index ad2098f99..0a1feb1f5 100644
--- a/go.mod
+++ b/go.mod
@@ -183,7 +183,7 @@ require (
 replace (
 	github.com/facebookincubator/nvdtools => github.com/stackrox/nvdtools v0.0.0-20231111002313-57e262e4797e
 
-	github.com/heroku/docker-registry-client => github.com/stackrox/docker-registry-client v0.1.0
+	github.com/heroku/docker-registry-client => github.com/stackrox/docker-registry-client v0.2.1
 
 	// The current latest version of github.com/mholt/archiver/v3 (v3.5.1) suffers from CVE-2024-0406.
 	// There is currently a PR in place to resolve it (https://github.com/mholt/archiver/pull/396),
diff --git a/go.sum b/go.sum
index e94e5c2cc..d181df379 100644
--- a/go.sum
+++ b/go.sum
@@ -612,8 +612,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
 github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace h1:9PNP1jnUjRhfmGMlkXHjYPishpcw4jpSt/V/xYY3FMA=
 github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
-github.com/stackrox/docker-registry-client v0.1.0 h1:TbNgSP3dhNbLAqlwyTIYNXbNvl9TDTAbh+cfzVyJ6II=
-github.com/stackrox/docker-registry-client v0.1.0/go.mod h1:4TU+pA11iczIvhtL0own2OJcJXc1o26tBHDivaXhlZU=
+github.com/stackrox/docker-registry-client v0.2.1 h1:0SxojNYZXV2tXo1BxtxfQpiPZavAmw+B1aWT8CSSqYE=
+github.com/stackrox/docker-registry-client v0.2.1/go.mod h1:4TU+pA11iczIvhtL0own2OJcJXc1o26tBHDivaXhlZU=
 github.com/stackrox/dotnet-scraper v0.0.0-20201023051640-72ef543323dd h1:vEjp7Q66zd4W72//Uk3uyVN50Mh/nFLbN9pb7CVK7mE=
 github.com/stackrox/dotnet-scraper v0.0.0-20201023051640-72ef543323dd/go.mod h1:HILeV3i/EyJz844GcrC3+oU7oZONhjfujaIYBMJ/bZE=
 github.com/stackrox/istio-cves v0.0.0-20221007013142-0bde9b541ec8 h1:rUIvoAHokPcd92aJT2gJwVeyE8tMuaqS5l5s3cEgXFY=
diff --git a/pkg/scan/scan.go b/pkg/scan/scan.go
index 24adae4bc..573fcc312 100644
--- a/pkg/scan/scan.go
+++ b/pkg/scan/scan.go
@@ -34,7 +34,7 @@ var manifestTypes = []string{
 	manifestV1.MediaTypeManifest,
 }
 
-// analyzeLayers processes all of the layers and returns the lineage for the last layer so that we can uniquely identify it
+// analyzeLayers processes all the layers and returns the lineage for the last layer so that we can uniquely identify it.
 func analyzeLayers(storage database.Datastore, registry types.Registry, image *types.Image, layers []string, uncertifiedRHEL bool) (string, error) {
 	var prevLayer string
 
@@ -44,7 +44,11 @@ func analyzeLayers(storage database.Datastore, registry types.Registry, image *t
 	for _, layer := range layers {
 		layerReadCloser := &LayerDownloadReadCloser{
 			Downloader: func() (io.ReadCloser, error) {
-				return registry.DownloadLayer(image.Remote, digest.Digest(layer))
+				dig, err := digest.Parse(layer)
+				if err != nil {
+					return nil, errors.Wrapf(err, "invalid layer digest %q", layer)
+				}
+				return registry.DownloadLayer(image.Remote, dig)
 			},
 		}
 
@@ -78,14 +82,14 @@ func ProcessImage(storage database.Datastore, image *types.Image, registry, user
 	if err != nil {
 		return "", err
 	}
-	digest, lineage, layer, err := process(storage, image, reg, uncertifiedRHEL)
+	dig, lineage, layer, err := process(storage, image, reg, uncertifiedRHEL)
 	if err != nil {
-		return digest, err
+		return dig, err
 	}
 	if image.SHA == "" {
-		image.SHA = digest
+		image.SHA = dig
 	}
-	return digest, storage.AddImage(layer, image.SHA, lineage, image.TaggedName(), &database.DatastoreOptions{
+	return dig, storage.AddImage(layer, image.SHA, lineage, image.TaggedName(), &database.DatastoreOptions{
 		UncertifiedRHEL: uncertifiedRHEL,
 	})
 }
@@ -93,21 +97,21 @@ func ProcessImage(storage database.Datastore, image *types.Image, registry, user
 // process fetches and analyzes the layers for the requested image returning the image digest, the lineage of the last layer and the last layer digest
 func process(storage database.Datastore, image *types.Image, reg types.Registry, uncertifiedRHEL bool) (string, string, string, error) {
 	logrus.Debugf("Processing image %s", image)
-	digest, layers, err := FetchLayers(reg, image)
+	dig, layers, err := FetchLayers(reg, image)
 	if err != nil {
-		return digest, "", "", err
+		return dig, "", "", errors.Wrapf(err, "fetching layers for image %s", image.String())
 	}
 	if len(layers) == 0 {
-		return digest, "", "", fmt.Errorf("No layers to process for image %s", image.String())
+		return dig, "", "", fmt.Errorf("no layers to process for image %s", image.String())
 	}
 
 	logrus.Infof("Found %v layers for image %v", len(layers), image)
 	lineage, err := analyzeLayers(storage, reg, image, layers, uncertifiedRHEL)
 	if err != nil {
 		logrus.Errorf("Failed to analyze image %q: %v", image.String(), err)
-		return digest, "", "", err
+		return dig, "", "", err
 	}
-	return digest, lineage, layers[len(layers)-1], err
+	return dig, lineage, layers[len(layers)-1], err
 }
 
 func isEmptyLayer(layer string) bool {
@@ -159,6 +163,9 @@ func handleManifestLists(reg types.Registry, remote, ref string, manifests []man
 		return "", nil, errors.Errorf("no valid manifests found for %s:%s", remote, ref)
 	}
 	if len(manifests) == 1 {
+		if err := manifests[0].Digest.Validate(); err != nil {
+			return "", nil, errors.Wrapf(err, "chosen manifest in list has invalid digest %s", manifests[0].Digest.String())
+		}
 		return handleManifest(reg, manifests[0].MediaType, remote, manifests[0].Digest.String())
 	}
 	var amdManifest manifestlist.ManifestDescriptor
@@ -169,6 +176,9 @@ func handleManifestLists(reg types.Registry, remote, ref string, manifests []man
 		}
 		// Matching platform for GOARCH takes priority so return immediately
 		if m.Platform.Architecture == runtime.GOARCH {
+			if err := m.Digest.Validate(); err != nil {
+				return "", nil, errors.Wrapf(err, "chosen manifest in list has invalid digest %s", m.Digest.String())
+			}
 			return handleManifest(reg, m.MediaType, remote, m.Digest.String())
 		}
 		if m.Platform.Architecture == "amd64" {
@@ -177,56 +187,60 @@ func handleManifestLists(reg types.Registry, remote, ref string, manifests []man
 		}
 	}
 	if foundAMD {
+		if err := amdManifest.Digest.Validate(); err != nil {
+			return "", nil, errors.Wrapf(err, "chosen manifest in list has invalid digest %s", amdManifest.Digest.String())
+		}
 		return handleManifest(reg, amdManifest.MediaType, remote, amdManifest.Digest.String())
 	}
 	return "", nil, errors.Errorf("no manifest in list matched linux and amd64 or %s architectures: %s:%s", runtime.GOARCH, remote, ref)
 }
 
-func handleManifest(reg types.Registry, manifestType, remote, ref string) (digest.Digest, []string, error) {
+// handleManifest returns the image digest and layers from the given image and manifest type.
+// The returned image digest and layers are valid unless the function returns a non-nil error.
+//
+// The caller is responsible for ensuring ref is a valid digest.
+func handleManifest(reg types.Registry, manifestType, remote, ref string) (dig digest.Digest, layers []string, err error) {
 	switch manifestType {
 	case manifestV1.MediaTypeManifest:
 		manifest, err := reg.Manifest(remote, ref)
 		if err != nil {
 			return "", nil, err
 		}
-		dig, err := renderDigest(manifest)
+		dig, err = renderDigest(manifest)
 		if err != nil {
 			return "", nil, err
 		}
-		layers := parseV1Layers(manifest)
-		return dig, layers, nil
+		layers = parseV1Layers(manifest)
 	case manifestV1.MediaTypeSignedManifest:
 		manifest, err := reg.SignedManifest(remote, ref)
 		if err != nil {
 			return "", nil, err
 		}
-		dig, err := renderDigest(manifest)
+		dig, err = renderDigest(manifest)
 		if err != nil {
 			return "", nil, err
 		}
-		layers := parseV1Layers(manifest)
-		return dig, layers, nil
+		layers = parseV1Layers(manifest)
 	case manifestV2.MediaTypeManifest:
 		manifest, err := reg.ManifestV2(remote, ref)
 		if err != nil {
 			return "", nil, err
 		}
-		dig, err := renderDigest(manifest)
+		dig, err = renderDigest(manifest)
 		if err != nil {
 			return "", nil, err
 		}
-		layers := parseLayers(manifest.Layers)
-		return dig, layers, nil
+		layers = parseLayers(manifest.Layers)
 	case registry.MediaTypeImageManifest:
 		manifest, err := reg.ManifestOCI(remote, ref)
 		if err != nil {
 			return "", nil, err
 		}
-		dig, err := renderDigest(manifest)
+		dig, err = renderDigest(manifest)
 		if err != nil {
 			return "", nil, err
 		}
-		return dig, parseLayers(manifest.Layers), nil
+		layers = parseLayers(manifest.Layers)
 	case manifestlist.MediaTypeManifestList:
 		manifestList, err := reg.ManifestList(remote, ref)
 		if err != nil {
@@ -240,8 +254,16 @@ func handleManifest(reg types.Registry, manifestType, remote, ref string) (diges
 		}
 		return handleManifestLists(reg, remote, ref, imageIndex.Manifests)
 	default:
-		return "", nil, fmt.Errorf("Could not parse manifest type %q", manifestType)
+		return "", nil, fmt.Errorf("could not parse manifest type %q", manifestType)
 	}
+
+	for _, layer := range layers {
+		if _, err := digest.Parse(layer); err != nil {
+			return "", nil, errors.Wrapf(err, "invalid layer %q", layer)
+		}
+	}
+
+	return dig, layers, nil
 }
 
 // FetchLayers downloads the layers for the given image.