The vulnerability in Frappe's client.set_value endpoint is fundamentally a type-confusion flaw. The security check validates the dictionary container passed as the 'fieldname' parameter before that dictionary gets decomposed into individual field names for processing. This means the validation inspects the type (a dictionary) rather than the substance (the actual field names nested within it). An attacker can supply a dictionary of protected fields that satisfies the container check but which the check never actually examines field-by-field—only after the validation passes does parsing occur, at which point the protected fields are now individual items that were never validated.
This creates an ergonomic trap: the security check exists, which creates false confidence. A code reviewer sees the forbidden-field validation and assumes it's sufficient, missing that it operates at the wrong abstraction layer. The mass-assignment amplification is significant—unlike single-field injection exploits, this grants access to every protected field simultaneously. These aren't arbitrary fields; they're protected because they connect to other security domains: owner flags, workflow state transitions, role assignments, link fields to privileged document types. Exploiting this means repositioning yourself in the permission topology, not just reading more data.
Any authenticated user can attempt exploitation, regardless of role permissions. This effectively bypasses Frappe's permission model at the application layer.
No fixed version is available. The attack surface grows with framework development—every new protected field added before a fix becomes a potential mass-assignment vector. Compensating controls like WAF rules cannot address this because the vulnerability lives entirely within the application's logic, not at the wire protocol level.