Skip to content

amp-download deletes valid attachments as "tampered" when stored digest is bare hex (sha256: prefix mismatch) #20

Description

@swickson

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions