{"record":{"id":"796d46a01e548609","repo":"theonedev/onedev","slug":"integrity-check-failed","errorCode":null,"errorMessage":"Integrity check failed: ","messagePattern":"Integrity check failed: ","errorType":"http","errorClass":"ClientException","httpStatus":400,"severity":"error","filePath":"server-plugin/server-plugin-pack-npm/src/main/java/io/onedev/server/plugin/pack/npm/NpmPackHandler.java","lineNumber":438,"sourceCode":"\t\t\t\t\t\t\t\t\t\t\tif (entry.getValue().equals(version))\n\t\t\t\t\t\t\t\t\t\t\t\tdistTagsOfVersion.add(entry.getKey());\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tvar distNode = versionMetadata.get(\"dist\");\n\t\t\t\t\t\t\t\t\t\tversionMetadata.remove(\"dist\");\n\n\t\t\t\t\t\t\t\t\t\tbyte[] versionMetadataBytes = writeJson(versionMetadata);\n\n\t\t\t\t\t\t\t\t\t\tif (distNode != null) {\n\t\t\t\t\t\t\t\t\t\t\tvar fileName = substringAfterLast(distNode.get(\"tarball\").asText(), \"-/\");\n\t\t\t\t\t\t\t\t\t\t\tvar fileContent = attachments.get(fileName);\n\t\t\t\t\t\t\t\t\t\t\tif (fileContent != null) {\n\t\t\t\t\t\t\t\t\t\t\t\tvar integrity = distNode.get(\"integrity\").asText();\n\t\t\t\t\t\t\t\t\t\t\t\tvar algorithm = substringBefore(integrity, \"-\");\n\t\t\t\t\t\t\t\t\t\t\t\tvar hash = Base64.decodeBase64(substringAfter(integrity, \"-\"));\n\t\t\t\t\t\t\t\t\t\t\t\tif (algorithm.equals(\"sha512\")) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (!Arrays.equals(decodeHex(Digest.sha512Of(fileContent).getHash()), hash)) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tthrow new ClientException(SC_BAD_REQUEST, \"Integrity check failed: \" + fileName);\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t} else if (algorithm.equals(\"sha1\")) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (!Arrays.equals(decodeHex(Digest.sha1Of(fileContent).getHash()), hash)) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tthrow new ClientException(SC_BAD_REQUEST, \"Integrity check failed: \" + fileName);\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\t\tvar errorMessage = String.format(\"Unexpected integrity algorithm (file: %s, algorithm: %s)\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfileName, algorithm);\n\t\t\t\t\t\t\t\t\t\t\t\t\tthrow new ClientException(SC_BAD_REQUEST, errorMessage);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\tvar packBlobId = packBlobService.uploadBlob(projectId, fileContent, null);\n\t\t\t\t\t\t\t\t\t\t\t\tvar sha256Hash = packBlobService.load(packBlobId).getSha256Hash();\n\t\t\t\t\t\t\t\t\t\t\t\tpack.setData(new NpmData(packageMetadataBytes, versionMetadataBytes, distTagsOfVersion, fileName, sha256Hash));\n\t\t\t\t\t\t\t\t\t\t\t\tpackService.createOrUpdate(pack, newArrayList(packBlobService.load(packBlobId)), true);\n\t\t\t\t\t\t\t\t\t\t\t\tresponse.setStatus(SC_CREATED);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-pack-npm/src/main/java/io/onedev/server/plugin/pack/npm/NpmPackHandler.java#L420-L456","documentation":"npm publish attachments carry an 'integrity' field (format '<algorithm>-<base64 hash>'). The handler verifies each attachment's bytes by hashing with the declared algorithm (sha512 or sha1) and comparing to the decoded hash. A mismatch throws ClientException HTTP 400 'Integrity check failed: <fileName>'; unsupported algorithms are also rejected.","triggerScenarios":"Publishing where an attachment's content differs from what its integrity hash was computed over — truncated or altered tarballs, wrong hash pasted into hand-built metadata, or an unsupported algorithm value.","commonSituations":"Corrupted uploads over flaky networks; scripts computing integrity over a different file version than embedded in 'data'; base64/hex encoding confusion when hand-crafting payloads; tampering or proxy rewriting of bodies.","solutions":["Re-run npm publish so integrity is recomputed from the actual attachment bytes","Verify the integrity string is '<algorithm>-<base64(hash)>' matching the exact data sent (use only sha512 or sha1)","Check for proxies/AV gateways modifying request bodies","Compare the local file's sha512 against the metadata integrity value before publishing"],"exampleFix":"// before (hand-built metadata)\n\"integrity\": \"sha256-...\"  // unsupported algorithm\n// after\n\"integrity\": \"sha512-<base64 of sha512 digest>\"","handlingStrategy":"validation","validationCode":"const crypto = require('crypto');\nfor (const [name, att] of Object.entries(meta._attachments)) {\n  const bytes = Buffer.from(att.data, 'base64');\n  const [alg, b64] = att.integrity.split('-');\n  if (!['sha512','sha1'].includes(alg)) throw new Error(`Unsupported integrity algorithm: ${alg}`);\n  const digest = crypto.createHash(alg).update(bytes).digest('base64');\n  if (digest !== b64) throw new Error(`Integrity mismatch for ${name}`);\n}","typeGuard":"function hasValidIntegrity(att) {\n  const [alg, b64] = (att?.integrity ?? '').split('-');\n  return (alg === 'sha512' || alg === 'sha1') && typeof b64 === 'string' && b64.length > 0;\n}","tryCatchPattern":"try { await publish() } catch (e) { if (e.response?.status === 400 && /Integrity check failed/i.test(e.message ?? '')) { console.error('Attachment bytes do not match integrity hash — republish with standard npm client'); } else throw e }","preventionTips":["Use standard npm publish so integrity is computed correctly","Only use sha512 or sha1 integrity values","Avoid proxies that rewrite request bodies","Verify hashes locally before scripted publishes"],"tags":["http-400","npm","integrity","checksum","publish"],"backgroundTag":"checksum-mismatch","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}