All Docs
FeaturesCalmony PayUpdated March 15, 2026

Security Fix: Cardstream Callback Signature Verification (SEC-05)

Security Fix: Cardstream Callback Signature Verification (SEC-05)

Release: v1.0.28
OWASP Category: A05:2021 — Security Misconfiguration
Severity: High
Affected file: src/app/api/v1/checkout/sessions/callback/route.ts


Background

When Cardstream processes a payment, it sends a POST callback to Calmony Pay's callback endpoint. To prove the request originated from Cardstream, the payload includes an HMAC-SHA512 signature field computed using a shared secret (CARDSTREAM_SIGNATURE_KEY). The callback handler is expected to recompute this signature and reject any request where the values do not match.


The Vulnerability

Prior to v1.0.28, the signature check was guarded by an if statement that required both a configured key and a present signature field:

// Before — vulnerable
if (signatureKey && fields.signature) {
  // HMAC verification ran here
  // if either condition was falsy, this block was skipped entirely
}
// execution continued regardless

This introduced two distinct bypass conditions:

ConditionEffect
CARDSTREAM_SIGNATURE_KEY not set in environmentVerification skipped; all callbacks accepted
Cardstream callback arrives without a signature fieldVerification skipped; callback accepted

In either case the handler would continue processing the callback as authentic, potentially updating a checkout session's status to succeeded without a real payment having occurred.

Impact

An attacker with knowledge of Calmony Pay's callback URL could craft an HTTP POST that mimics a successful Cardstream payment notification. Without signature verification, this forged request would be accepted and could:

  • Mark a checkout session as succeeded
  • Trigger downstream fulfilment, licence provisioning, or subscription activation
  • Cause real financial discrepancy between Cardstream's records and Calmony Pay's ledger

The Fix

Signature verification is now unconditional in production. The logic has been restructured so that a missing key or a missing signature are both treated as hard failures.

// After — fixed
if (!signatureKey) {
  // CARDSTREAM_SIGNATURE_KEY is not configured — refuse to process
  return errorResponse(500, 'Signature verification is not configured');
}

if (!fields.signature) {
  // Callback arrived without a signature — treat as failed verification
  return redirect(cancelUrl);
}

// Proceed with HMAC-SHA512 comparison
const valid = verifySignature(fields, signatureKey);
if (!valid) {
  return redirect(cancelUrl);
}

Test-mode bypass

A controlled bypass is still available for local development, automated tests, and CI environments where a real Cardstream connection is not present. The bypass is activated by setting either:

  • NODE_ENV=test
  • REQUIRE_SIGNATURE=false

This must be set explicitly and intentionally; the bypass is never the default.


Action Required for Self-Hosted Deployments

If you run Calmony Pay in your own infrastructure, take the following steps before or immediately after deploying v1.0.28:

  1. Ensure CARDSTREAM_SIGNATURE_KEY is set in every production and staging environment that processes real Cardstream callbacks. The callback endpoint will return 500 if this variable is absent.
  2. Do not set REQUIRE_SIGNATURE=false in any environment that handles real payments.
  3. Review your environment variable management to ensure secrets are injected at runtime and not accidentally omitted during deployments.

Environment Variables Reference

VariableRequired in ProductionDescription
CARDSTREAM_SIGNATURE_KEY✅ YesShared secret used to verify Cardstream HMAC-SHA512 callback signatures. Obtain from your Cardstream merchant portal.
REQUIRE_SIGNATURESet to false only in test/CI environments to bypass signature verification. Never set in production.

OWASP Reference

This issue is classified under OWASP Top 10 A05:2021 — Security Misconfiguration, which covers cases where missing, incomplete, or insecure default configurations leave an application vulnerable. The root cause here is a conditional verification pattern that silently degrades to no verification when a configuration value is absent.