Skip to content

Security: HandyPlugins/emdash-payments

Security

SECURITY.md

Security

Report suspected vulnerabilities privately to support@handyplugins.co. Include Payments and EmDash versions and synthetic reproduction steps. Never send API keys, signing secrets, card details, real customer data or raw logs.

Payments runs inside EmDash's sandbox. Its only additional capability is HTTPS access to api.stripe.com. Credentials are EmDash encrypted secret settings using AES-GCM, random nonces and authenticated plugin/setting identity; keep the site's encryption keys with secure operational backups. Secret inputs are masked and normal admin blocks never echo credentials. Database verification confirmed encrypted envelopes for both configured Stripe secrets.

Public webhook requests use exact bytes, an explicitly forwarded stripe-signature header, the endpoint's signing secret and Stripe's official async verification with a five-minute timestamp tolerance. Nothing is parsed or stored before verification. Verified events are claimed atomically and retried after failed processing or an expired lease. Stripe state is retrieved before reconciliation and compared with immutable server-created offer snapshots.

Payment and customer writes are separate atomic operations, not one transaction. Deterministic keys and bounded compare-and-set retries make interrupted replay converge without duplicate payments/customers. Successful payments are terminal in this release; refunds are not synchronized. Never use a success page as proof of payment or grant access from an email address alone.

Only site administrators can access local payment/customer information. No financial operations are exposed through MCP. This package stores no cards, CVCs, full billing addresses, payment-method details or raw webhook payloads. Basic customer email/name/country and payment history use regular plugin storage, without additional field encryption. Protect the database and backups with appropriate filesystem access and storage encryption; secret-setting encryption does not encrypt the entire database.

Deleting credentials does not deactivate existing Stripe-hosted links. Disable links before removing credentials, or disable them directly in Stripe. Do not change Stripe accounts while an offer update is unresolved. API-side object creation can succeed even if a response is lost: pending updates retain their idempotency keys and stop automatic replay after 23 hours. Older uncertain updates require inspecting Stripe request logs before manual recovery.

There aren't any published security advisories