{"record":{"id":"efad35e1d9ca45ec","repo":"lima-vm/lima","slug":"invalid-digest-algorithm-q","errorCode":null,"errorMessage":"invalid digest algorithm %#q","messagePattern":"invalid digest algorithm %#q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/downloader/downloader.go","lineNumber":617,"sourceCode":"}\n\n// cacheDirectoryPath returns the cache subdirectory path.\n//   - \"url\" file contains the url\n//   - \"data\" file contains the data\n//   - \"time\" file contains the time (Last-Modified header)\n//   - \"type\" file contains the type (Content-Type header)\nfunc cacheDirectoryPath(cacheDir, remote string) string {\n\treturn filepath.Join(cacheDir, \"download\", \"by-url-sha256\", CacheKey(remote))\n}\n\n// cacheDigestPath returns the cache digest file path.\n//   - \"<ALGO>.digest\" contains the digest\nfunc cacheDigestPath(shad string, expectedDigest digest.Digest) (string, error) {\n\tshadDigest := \"\"\n\tif expectedDigest != \"\" {\n\t\talgo := expectedDigest.Algorithm().String()\n\t\tif strings.Contains(algo, \"/\") || strings.Contains(algo, \"\\\\\") {\n\t\t\treturn \"\", fmt.Errorf(\"invalid digest algorithm %#q\", algo)\n\t\t}\n\t\tshadDigest = filepath.Join(shad, algo+\".digest\")\n\t}\n\treturn shadDigest, nil\n}\n\nfunc IsLocal(s string) bool {\n\treturn !strings.Contains(s, \"://\") || strings.HasPrefix(s, \"file://\")\n}\n\n// canonicalLocalPath canonicalizes the local path string.\n//   - Make sure the file has no scheme, or the `file://` scheme\n//   - If it has the `file://` scheme, strip the scheme and make sure the filename is absolute\n//   - Expand a leading `~`, or convert relative to absolute name\nfunc canonicalLocalPath(s string) (string, error) {\n\tif s == \"\" {\n\t\treturn \"\", errors.New(\"got empty path\")\n\t}","sourceCodeStart":599,"sourceCodeEnd":635,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/downloader/downloader.go#L599-L635","documentation":"cacheDigestPath builds the digest file name \"<ALGO>.digest\" inside the cache directory, using the algorithm string from the expected digest. Because that string becomes a path component, it is validated to contain no path separators; an algorithm containing '/' or '\\' is rejected with this error to prevent path traversal or invalid cache filenames.","triggerScenarios":"Passing WithExpectedDigest(digest.Digest) whose algorithm string contains a slash or backslash (e.g. a malformed digest string like \"sha/x256:...\" or a hand-built digest) to Download/Cached — raised from getCached, fetch, or Cached via cacheDigestPath.","commonSituations":"Digest strings built by hand or parsed from untrusted config instead of using go-digest's digest.Parse, which would have rejected them earlier; typos in a digest annotation in a template YAML.","solutions":["Validate the digest before use: d, err := digest.Parse(s) — this rejects malformed algorithms early with a clearer error","Use only supported algorithms (sha256, sha512) in configuration; fix typos in the digest string","Ensure digests come from trusted sources (upstream metadata) rather than arbitrary user input","If the digest originates in a Lima template, correct the digests field to a valid \"algo:hex\" value"],"exampleFix":"// before\nexpected := digest.Digest(req.Digest) // \"sha/256:abc...\"\n// after\nexpected, err := digest.Parse(req.Digest)\nif err != nil {\n    return fmt.Errorf(\"invalid digest %q: %w\", req.Digest, err)\n}","handlingStrategy":"validation","validationCode":"import \"github.com/opencontainers/go-digest\"\nfunc validateDigest(s string) (digest.Digest, error) {\n    d, err := digest.Parse(s) // rejects malformed algorithms before cacheDigestPath sees them\n    if err != nil { return \"\", fmt.Errorf(\"invalid digest %q: %w\", s, err) }\n    if algo := d.Algorithm().String(); strings.ContainsAny(algo, \"/\\\\\") {\n        return \"\", fmt.Errorf(\"unsupported algorithm %q\", algo)\n    }\n    return d, nil\n}","typeGuard":"func isSafeDigest(d digest.Digest) bool {\n    if d == \"\" { return true }\n    algo := d.Algorithm().String()\n    return !strings.ContainsAny(algo, \"/\\\\\")\n}","tryCatchPattern":"res, err := downloader.Download(url, downloader.WithExpectedDigest(d))\nif err != nil && strings.Contains(err.Error(), \"invalid digest algorithm\") {\n    return fmt.Errorf(\"digest from config is malformed; use digest.Parse at load time: %w\", err)\n}","preventionTips":["Always construct digests with digest.Parse or digest.FromBytes, never by casting strings","Validate digests when loading config/templates, not at download time","Restrict allowed algorithms to sha256/sha512 in your config layer","Treat external/user-supplied digests as untrusted input and validate early"],"tags":["go","validation","digest","path-traversal"],"backgroundTag":"invalid-digest-algorithm","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}