| Version | Supported |
|---|---|
| 1.2.x | ✅ |
| 1.0.x – 1.1.x | ❌ — upgrade |
| < 1.0 | ❌ |
Releases before 1.2.0 verify payments without comparing the settled amount to the ordered one, which lets a payment token replayed onto another order verify cleanly; AsanPardakht and Sepehr additionally accept a settlement key chosen by the payer. See the 1.2.0 changelog for the full list.
Please do not open a public issue.
Use GitHub's private reporting — Security → Report a vulnerability — and include:
- the affected version and gateway,
- what an attacker can achieve,
- a reproduction, with all credentials, tokens, card numbers and IBANs redacted.
You can expect a first answer within a week and a fix or a plan within a month, depending on severity.
Payvand handles money and terminal credentials, so the interesting classes are:
- a verification path that reports success when the provider did not settle the payment,
- an amount that can be influenced by the payer (the callback is never trusted for amounts — a way around that is a bug),
- credentials, tokens or PANs leaking into logs, errors or the
Rawfields, - a flaw in the signing or envelope code under
internal/cryptox, - a callback parser that can be made to attribute a payment to the wrong order.
- A provider rejecting a request because its own API changed. Open a normal issue.
- Weak algorithms mandated by an acquirer's protocol — 3DES-ECB for Sadad, RSA over SHA-1 for Pasargad. They are the providers' contracts; Payvand implements them and documents them as such.
- Never build the verification amount from the callback. Read it from your own
order —
Callback.VerifyRequest(amount)is shaped to make that the easy path. - Treat
Callback.Succeededas a hint. A payment is final only whenVerifyreturns without error. - Store the payment token before redirecting the payer; it is the only handle on the transaction afterwards.
- Keep terminal keys out of the repository.
.gitignorealready excludes*.pem,*.key,*.p12andkeys/. - The logger receives request and response bodies with the credential fields
masked — Iranian gateways authenticate on the body, so Mellat's
userPassword, Parsian'sLoginAccount, Pay.ir'sapi, Zibal'smerchant, TOP'sPinand the OAuth password grants never reach it.RawandPurchaseResponse.Extraare not masked: they carry the provider's answer verbatim for support and auditing, so redact them yourself before they reach a log aggregator. - Leave
WithSkipTLSVerifyoff unless a Shaparak host genuinely serves an incomplete chain, and scope it to that gateway only.