Security and fraud checks
How OpenPromoter protects tenants, money, secrets and webhooks. See the fraud checks that every plan runs and how to report a vulnerability.
Money
- Payouts are created as
awaiting_approval. Only a signed-in owner, admin or finance team member can approve them. API keys, the MCP server, Autopilot and every AI feature can prepare payouts but cannot approve them. - On approval the commissions are locked to the payout inside a database transaction before any provider is called. Every provider call carries an idempotency key.
- Approving a payout batch above the program's threshold ($1,000 by default) needs two-factor authentication and a fresh code.
- US partners paid outside Stripe need a W-9 with a TIN on file before crossing the 1099-NEC threshold.
- Every money and permission action is written to the audit log, viewable in Settings > Audit log.
Accounts and access
- Roles: owner, admin, finance and viewer. Money changes need a role with money permissions.
- Two-factor authentication (TOTP) for every user.
- Every route resolves the program through a membership check, and API keys are scoped to one workspace. Tenant isolation has its own tests.
- API keys are shown once, stored as SHA-256 hashes, carry explicit scopes and can be revoked.
- Login and API rate limits.
Secrets and data
- Secrets come from environment variables only.
- Billing and payout credentials and partner tax ids are encrypted at rest with AES-256-GCM using
ENCRYPTION_KEY. - IP addresses are stored as salted hashes. No personal data is written to logs.
- Server-side fetches of user-supplied URLs (brand extraction, webhooks) are blocked from reaching private networks.
Webhooks
- Incoming: signatures are verified for Stripe, Paddle, Lemon Squeezy and Polar. Chargebee requests are checked against their basic-auth credentials. Each event is processed once.
- Outgoing: signed with
OpenPromoter-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, "t.body")>and retried with exponential backoff. See Webhooks.
Inputs
- Every API input is validated with a schema.
- Server actions are origin-checked against CSRF, and cookie-authenticated API routes check
Origin.
Fraud checks
Every program on every plan scores partners and new referrals on these signals:
| Signal | What it looks for |
|---|---|
| Self-referral | The partner and the customer are the same person including email aliases |
| Same network as partner | Clicks or signups from the partner's own IP address |
| Duplicate accounts | Several referred accounts that look like one person |
| Payout account shared with another partner | The same PayPal or Wise account on more than one partner |
| Recruited own account | A two-tier recruit with the recruiter's email, login, signup network or payout account |
| Coupon leaking | Coupon sales with no partner click (for example codes posted on coupon sites) |
| Paid ads on your brand | Clicks from paid search ads (gclid, msclkid and similar) |
| Suspicious click pattern | Bursts of clicks that do not behave like people |
| Bot traffic | Crawler, headless and scripted user agents |
| Refunds after payout | Customers who refund once the commission has been paid |
| Customers cancel fast | Referred customers who churn unusually quickly |
Signals combine into a 0 to 100 risk score. Commissions on referrals above the program's threshold are held for review instead of being approved. In the review queue you dismiss each flag ("Looks fine") or confirm it to ban the partner and keep their commissions held.
Personal data (GDPR)
- Erase personal data on a partner's page removes their personal details while keeping commissions and payouts in the ledger for accounting.
- Every user can download their own account data from
/api/account/export. - Workspace owners can export the whole workspace as JSON from
/api/export/workspace?workspace=<id>.
Planned next
- Matching Stripe payment-method fingerprints across partners and customers.
- Stripe Accounts v2 for partner payouts. Partner payouts use Connect Express accounts today.
- Sending PayPal payouts again when they come back unclaimed after 30 days.
Reporting a vulnerability
Please report security issues privately through GitHub's private vulnerability reporting on the openpromoter/openpromoter repository. Do not open a public issue. Include steps to reproduce and the version you tested.