fix(payments): reject HTML-special chars in product titles (VK payment guard)
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 20s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m52s

A product title containing & < > " ' silently breaks VK purchases: VK
HTML-escapes the character in its order_status_change payment-callback echo
(e.g. " -> &quot;) but signs the notification over a different form, so the
gateway's signature check no longer matches ("vk callback: bad signature")
and the purchase never confirms — while get_item (whose request carries no
title) still passes.

validateProduct now rejects those characters at the admin catalog editor —
the single write path for CreateProduct/UpdateProduct/SetProductActive — so a
title can't reintroduce the break. Reject, not transform: the operator retypes
a clean title (« » guillemets, not straight quotes), so the stored value stays
identical everywhere (storefront, wallet, VK box).

Docs: docs/PAYMENTS.md §7 + agent field notes; Go Doc on validateProduct.
Test: validateProduct HTML-special-char cases. No wire/schema change.
This commit is contained in:
Ilia Denisov
2026-07-16 20:57:04 +02:00
parent 69246eb0c0
commit f60327c1ce
4 changed files with 34 additions and 6 deletions
+7
View File
@@ -192,6 +192,13 @@ live in the database and are edited in the admin console, no release required.
purchase stores a **snapshot** of what was sold (atom composition + price at the time) into
an archive, so history/receipts/tax are independent of later catalog edits.
**Titles reject HTML-special characters.** The admin editor refuses a product title containing
`& < > " '` (`validateProduct`). VK HTML-escapes such characters in its `order_status_change`
payment-callback echo (e.g. `"``&quot;`) but computes the notification signature over a different
form, so our callback signature check no longer matches and the purchase silently fails to confirm —
while the `get_item` phase (whose request carries no title) still passes. Use « » guillemets, not
straight quotes.
## 8. Trusted platform signal
The gate (§4) needs a **trusted, unforgeable** platform context on the server. The client is