This CVE is a SQL injection in a WordPress plugin's dynamic form field feature, and it succeeds because multiple layers each assumed another layer handled sanitization — a textbook case of defense in depth that creates the exact gap each layer was designed to close.

The vulnerable code uses a {username} placeholder in a SQL WHERE clause for form choices that are dynamically populated from the database. The placeholder resolves to the authenticated user's display_name field. The developers' reasoning was sound by their mental model: the authenticated user controls their own display_name, so the input is controlled by a user — just not safely. display_name is user-editable by design, and WordPress correctly escapes it for HTML output because that's its intended context. The plugin inherited that assumption and applied it to SQL — a context WordPress never designed for, because it shouldn't need to.

The fix is straightforward but the location matters: the escaping must wrap the resolved display_name value at the point of template substitution, before it enters the SQL string. Using esc_sql() at the display stage (where WordPress already uses it) won't help — the injection happens earlier in the query construction pipeline. Any code using {username} or similar user-supplied placeholders in SQL templates should be audited.

The prerequisite structure — authenticated subscriber access, a specifically configured form with DB-backed dynamic choices — looks like a narrow attack surface but isn't. Subscriber registration is default on most WordPress sites, display_name is user-editable by default, and dynamic-choice fields are a documented feature, not an obscure edge case. CVSS 5.3 undersells this by treating configuration prerequisites as narrowing the surface when they're often present by default.

This assumption pattern — "the authenticated user's own field is safe for SQL because they can only harm themselves" — has appeared at least four times in WordPress plugin history. Each recurrence teaches the same lesson: the security boundary isn't the user's intent, it's the code's context. The fix for this specific instance will teach future developers to esc_sql() display_name. It won't teach them to audit new substitution contexts — and that's where the next recurrence is already waiting.