Security & Server-Only Keys
Payment gateway integration errors frequently result in high-severity security vulnerabilities. nepay is built with a defense-in-depth architecture to eliminate common failure modes.
⚠️ The Server-Only Rule
Section titled “⚠️ The Server-Only Rule”If a secret key is exposed in browser JavaScript:
- Attackers can sign arbitrary fraudulent eSewa payment callbacks and mark orders paid.
- Attackers can issue unauthorized API queries and refunds directly to your Khalti merchant balance.
All calls to initiatePayment() and verifyPayment() must execute strictly in backend code:
- Node.js / Express / Fastify / Koa / NestJS route handlers
- Next.js Server Actions or Route Handlers (
app/api/.../route.ts) - Serverless functions (AWS Lambda, Google Cloud Functions)
Zero Secret Logging
Section titled “Zero Secret Logging”The SDK adheres to a strict zero-leak logging discipline:
- No secrets are printed in logs.
- Error messages do not concatenate or echo secret keys.
- Gateway payloads included in the normalized
rawresult only contain non-sensitive gateway response bodies.
Constant-Time HMAC Signature Comparison
Section titled “Constant-Time HMAC Signature Comparison”When verifying eSewa callback signatures, standard string comparison (a === b) is vulnerable to timing attacks, where an attacker measures slight microsecond timing differences to infer byte values.
nepay uses crypto.timingSafeEqual:
import { timingSafeEqual } from "node:crypto";
function constantTimeEq(a: string, b: string): boolean { const ab = Buffer.from(a, "utf8"); const bb = Buffer.from(b, "utf8"); if (ab.length !== bb.length) return false; return timingSafeEqual(ab, bb);}This ensures that the time taken to evaluate the signature remains constant regardless of how many bytes match.
Unique Transaction IDs Per Attempt
Section titled “Unique Transaction IDs Per Attempt”Never reuse an order ID across multiple payment attempts. If a customer abandons a checkout or their card expires, minting a new attempt ID (e.g. ORDER_101_ATTEMPT_1, ORDER_101_ATTEMPT_2 or UUID) prevents:
- Idempotency collisions at Khalti.
- Replay attacks where an old completed payment is claimed for a new order.