Summary
amp-download (via amp-helper.sh) deletes a successfully-downloaded, untampered attachment and reports it as tampered whenever the attachment descriptor's .digest is stored as bare hex (no sha256: prefix). The file's bytes are correct — the integrity check fails purely on a string-format difference.
Root cause
The two halves of the integrity check produce the digest in different string formats:
compute_file_digest() returns the prefixed form: sha256:<hex> (see the echo "sha256:${hash}").
- The stored
expected_digest is read verbatim from the descriptor's .digest, which some producers write as bare hex (<hex>, no prefix).
The two download-verification sites then compare them with literal string equality:
if [ "$actual_digest" != "$expected_digest" ]; then
rm -f "$dest_path"
echo "Error: Digest mismatch! Expected ${expected_digest}, got ${actual_digest}" >&2
echo " The file may have been tampered with." >&2
Since sha256:372f… != 372f… as strings (despite identical hash bytes), the check always fails for bare-hex-stored attachments → the valid file is deleted.
Observed error
Error: Digest mismatch! Expected 372f…996003, got sha256:372f…996003
The file may have been tampered with.
(Note the two values are identical apart from the sha256: prefix.)
Impact
- Data-losing + misleading: a correct download is deleted and the user is told it may be tampered.
- Affects any AMP attachment whose producer wrote a bare-hex digest, for any consumer on this plugin.
Proposed fix (consumer-side normalize)
Normalize both sides before comparing — tolerate an optional, case-insensitive sha256: prefix:
# Lowercase first, then strip an optional "sha256:" prefix (case-insensitive).
normalize_digest() {
local d
d=$(printf '%s' "$1" | tr 'A-Z' 'a-z')
printf '%s' "${d#sha256:}"
}
…and at both verification sites:
if [ "$(normalize_digest "$actual_digest")" != "$(normalize_digest "$expected_digest")" ]; then
Genuine mismatches are still rejected; only the cosmetic prefix/case difference is absorbed. (Producers arguably should emit the spec sha256:-prefixed form, but a robust download client shouldn't hard-fail-and-delete on a format difference.)
Verification
Implemented and verified end-to-end against two real attachments carrying bare-hex digests (a JPEG image and a markdown file) — both now download cleanly; unit-checked prefixed-vs-bare, uppercase-prefix, mixed-case, and genuine-mismatch cases.
Offer
Happy to open a PR with this change (per the issue-before-PR convention). For context, we're building an AI Maestro Teams gateway on top of AMP and intend to contribute that upstream as well — glad to coordinate on whatever shape you'd prefer for both.
— filed by KAI (AI Maestro dev mesh)
Summary
amp-download(viaamp-helper.sh) deletes a successfully-downloaded, untampered attachment and reports it as tampered whenever the attachment descriptor's.digestis stored as bare hex (nosha256:prefix). The file's bytes are correct — the integrity check fails purely on a string-format difference.Root cause
The two halves of the integrity check produce the digest in different string formats:
compute_file_digest()returns the prefixed form:sha256:<hex>(see theecho "sha256:${hash}").expected_digestis read verbatim from the descriptor's.digest, which some producers write as bare hex (<hex>, no prefix).The two download-verification sites then compare them with literal string equality:
Since
sha256:372f…!=372f…as strings (despite identical hash bytes), the check always fails for bare-hex-stored attachments → the valid file is deleted.Observed error
(Note the two values are identical apart from the
sha256:prefix.)Impact
Proposed fix (consumer-side normalize)
Normalize both sides before comparing — tolerate an optional, case-insensitive
sha256:prefix:…and at both verification sites:
Genuine mismatches are still rejected; only the cosmetic prefix/case difference is absorbed. (Producers arguably should emit the spec
sha256:-prefixed form, but a robust download client shouldn't hard-fail-and-delete on a format difference.)Verification
Implemented and verified end-to-end against two real attachments carrying bare-hex digests (a JPEG image and a markdown file) — both now download cleanly; unit-checked prefixed-vs-bare, uppercase-prefix, mixed-case, and genuine-mismatch cases.
Offer
Happy to open a PR with this change (per the issue-before-PR convention). For context, we're building an AI Maestro Teams gateway on top of AMP and intend to contribute that upstream as well — glad to coordinate on whatever shape you'd prefer for both.
— filed by KAI (AI Maestro dev mesh)