# A Signature Must Bind Its Purpose Not Only Its Data ## Claim A cryptographic signature or hash only proves that a site's secret produced a given string, not that the string was produced *for the purpose the verifier assumes*, so any system that calls the same signing function in two unrelated contexts without a context-specific prefix lets an attacker mint a token honestly in one context and spend it in another without ever forging or recovering anything. <!-- atomicity: 1 idea ✓ --> ## Scope & conditions - Applies wherever one signing or hashing primitive (a bare HMAC, `wp_hash()`, a signed URL, a JWT without an audience claim) is reused across more than one security-relevant purpose in the same codebase. - Strongest when one of the two contexts accepts attacker-influenced input (a public page URL, a user-chosen filename) — that's what lets the attacker choose which "legitimate" token gets minted. - The fix is domain separation: a versioned, purpose-specific prefix baked into what gets signed, so a token minted for context A cannot verify in context B even though the same secret and algorithm produced it. - Doesn't require the secret to leak and doesn't require any flaw in the hash function itself — the primitive can be cryptographically perfect and the bug still exists entirely at the design layer, which is why it survives ordinary code review: each call site looks correct in isolation. ## Evidence > [!quote] ID:rw_01m1pqbrnw8mf8nfpjx069qz7f > "This is a cryptographic domain-confusion issue: the attacker does not need to recover the site's secret or forge a new hash, but instead reuses a legitimate hash generated for a different purpose." Wordfence's Argus system (an in-house AI finder) identified this in Gravity Forms ≤3.0.2 (CVE-2026-19513, CVSS 8.1): `wp_hash()` was used both to hash a public page URL as part of form state and, with no context prefix, to authenticate chunked-upload continuation values. Because the page URL is attacker-controlled, an attacker could request a URL that serialized to the exact string the upload handler expected, producing a hash that verified as a legitimate upload-continuation token. Combined with a verify-then-sanitize ordering bug, this enabled unauthenticated arbitrary file upload — RCE on NGINX, stored XSS where `.htaccess` blocked PHP execution. The 3.0.3 patch replaced the bare hash with a versioned, domain-separated HMAC (`gravityforms-upload-chunk-v1|`) binding filename, chunk number, form/field IDs, offset, and total chunks, using `wp_salt('auth')`. ## Links - [[3. Resources/Permanent Notes/Client-Supplied Hints Are Not Security Boundaries]] — because extends: both concern the gap between "a value passed the check" and "the value proves what the verifier needs it to prove" — that note is about trusting an unverified client hint, this one is about a verified signature that was never scoped to say what it's being used to prove. - [[3. Resources/MOCs/WordPress Platform Design MOC]] — because this is a platform-primitive design gap (core's `wp_hash()` carries no domain-separation guidance) rather than a one-plugin bug, and the fix belongs in how the platform documents or wraps the primitive. ## Tests / falsifiers - Audit other WordPress plugins for `wp_hash()` or similar bare-hash calls used at more than one security-relevant site with no context prefix — a meaningful hit rate would confirm this as a class, not a one-off. - Find a case where a domain-separated token was still exploited by an attacker able to influence the prefix itself — would show the fix is necessary but not sufficient. ## Source - [[3. Resources/Readwise/Full Document Contents/Articles/Wordfence Argus Finds Unauthenticated Arbitrary File Upload Vulnerability in Gravity Forms]] — Wordfence advisory, 2026-09-01, by Alex Thomas; vendor content (the finder is Wordfence's own AI system, Argus) but with published, checkable code excerpts for the vulnerable logic and the patch. Verify install-count and timeline claims independently before citing.