Skip to content

SPDX package verification code is the SHA1 of empty input when files are hashed without SHA1 #5441

Open

Description

@eriknordmark

What happened:

When files are hashed without SHA1, the SPDX output gives packages that
contain files filesAnalyzed: true and the package verification code
da39a3ee5e6b4b0d3255bfef95601890afd80709, which is the SHA1 of empty
input. The code verifies nothing: every such package gets the same value,
whatever files it contains.

newPackageVerificationCode in
syft/format/common/spdxhelpers/to_format_model.go looks for a sha1
digest of each contained file, and when there is none it still appends the
zero file.Digest:

var d file.Digest
for _, digest := range digest {
	if digest.Algorithm == "sha1" {
		d = digest
		break
	}
}
digests = append(digests, d)

So the list is non-empty, the concatenated values are the empty string, and
the returned code makes toPackages set filesAnalyzed = true.

This affects every library user that keeps the default file configuration:
filecataloging.DefaultConfig() hashes with SHA256 only, unlike the CLI's
sha1, sha256 default. docker/buildkit-syft-scanner, which generates
BuildKit's SBoM attestations, calls syft.DefaultCreateSBOMConfig() and so
emits this code for the apk packages in the images it scans.

What you expected to happen:

No package verification code, and filesAnalyzed: false, when a contained
file has no SHA1, as suggested in #1256. Hashing SHA1 whenever the output
is SPDX, which needs it for files (§8.4) and for this code (§7.9), would
avoid the case altogether.

Steps to reproduce the issue:

docker run --rm -e SYFT_FILE_METADATA_DIGESTS=sha256 \
  -v /var/run/docker.sock:/var/run/docker.sock anchore/syft:v1.54.1 \
  docker:alpine:3.22 -o spdx-json -q \
  | jq -r '.packages[] | select(.name=="busybox" or .name=="musl" or .name=="zlib")
           | [.name, .filesAnalyzed, .packageVerificationCode.packageVerificationCodeValue] | @tsv'
busybox	true	da39a3ee5e6b4b0d3255bfef95601890afd80709
musl	true	da39a3ee5e6b4b0d3255bfef95601890afd80709
zlib	true	da39a3ee5e6b4b0d3255bfef95601890afd80709

busybox contains 7 files in that document. With the default digests the
codes differ per package, and busybox's matches the SHA1 of its files'
sorted SHA1s.

Anything else we need to know?:

Related: #1256 (SPDX output without SHA1). The function is unchanged on
main.

Environment:

  • Output of syft version: 1.54.1 (anchore/syft:v1.54.1); also seen with 1.51.0 in docker/buildkit-syft-scanner:1.12.0
  • OS: Linux

Activity

  1. nightjard commented on Oct 18, 2026

    @nightjard

    Hi! I’d like to investigate this and add regression tests for SHA256-only configurations. Should missing SHA1 hashes mean omitting the verification code and setting filesAnalyzed to false?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions