Server-side receipt validation with App Store Server API v2 or Google RTDN
Why it matters
Client-side receipt validation is trivially bypassed: any user with a proxy tool (Charles Proxy, mitmproxy) can intercept the platform's receipt response and return a forged success. This is OWASP A07 (Identification & Authentication Failures) applied to entitlement decisions — the access control check runs in an environment the attacker fully controls. CWE-345 (Insufficient Verification of Data Authenticity) is the direct mapping. The business consequence is that paid features become free for any motivated user. Apple deprecated the legacy /verifyReceipt endpoint in favor of App Store Server API v2 (JWT-signed transactions, api.storekit.itunes.apple.com) — apps still using the legacy endpoint face a compounding validation gap as it is phased out.
Severity rationale
High because client-side receipt validation is bypassable by any user with a network proxy, allowing paid features to be unlocked without payment.
Remediation
Move receipt validation to a server you control, or delegate it to a third-party SDK backend (RevenueCat, Adapty, Qonversion). Never make entitlement decisions solely from a success callback in the app process.
The simplest path uses RevenueCat (free tier available) — customerInfo.entitlements.active is server-validated:
// After purchase — check server-validated entitlements, not the purchase callback alone
const customerInfo = await Purchases.getCustomerInfo();
const isPremium = customerInfo.entitlements.active['premium'] !== undefined;
For a custom backend using Apple's App Store Server API v2 (migrate away from the deprecated /verifyReceipt):
// POST /api/validate-purchase (server-side)
const client = new AppStoreServerAPIClient(
privateKey, keyId, issuerId, bundleId, Environment.PRODUCTION
);
const txInfo = await client.getTransactionInfo(transactionId);
Store validated entitlement state in your database keyed to the user ID (src/lib/entitlements.ts or equivalent) — never to the device alone.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the App Store IAP & Subscriptions Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-345 — Insufficient Verification of Data Authenticity
- owasp:2021 · A07 — Identification and Authentication Failures
- external · apple-app-store-server-api-v2 — Apple App Store Server API v2 — Receipt Validation
Taxons
History
- 2026-04-18·v1.0.0·Initial import from app-store-iap-subscriptions·automated