| शीर्षक | mickasmt next-saas-stripe-starter 1.0.0 Authorization Bypass |
|---|
| विवरण | https://github.com/mickasmt/next-saas-stripe-starter
IDOR on Stripe Customer Portal — Access Any User's Billing
File: `actions/open-customer-portal.ts` (lines 16–35)
Called from: components/forms/customer-portal-button.tsx` → `components/pricing/billing-info.tsx`
CWE: CWE-639 (Authorization Bypass Through User-Controlled Key)
OWASP A01:2021 – Broken Access Control
The vulnerability: The `openCustomerPortal` action receives `userStripeId` directly from the client and passes it straight to the Stripe API without verifying that the Stripe customer ID belongs to the authenticated user:
```typescript
export async function openCustomerPortal(userStripeId: string): Promise<responseAction> {
// ...
const session = await auth();
if (!session?.user || !session?.user.email) {
throw new Error("Unauthorized");
}
if (userStripeId) {
const stripeSession = await stripe.billingPortal.sessions.create({
customer: userStripeId, // attacker-controlled, never verified
return_url: billingUrl,
});
redirectUrl = stripeSession.url as string;
}
// ...
}
```
The `CustomerPortalButton` component receives `userStripeId` as a prop and binds it to the action: `openCustomerPortal.bind(null, userStripeId)`. An attacker can intercept or modify this call to pass any Stripe customer ID.
Attack scenario:
1. Attacker obtains or guesses another user's Stripe customer ID (e.g., `cus_XXXXX` — these are sequential/predictable).
2. Calls the `openCustomerPortal` server action with the victim's Stripe customer ID.
3. Receives a valid Stripe billing portal URL for the victim's account.
4. Can view, modify, or cancel the victim's subscription, view payment methods, and access billing history.
Fix: Look up the authenticated user's Stripe customer ID from the database instead of trusting client input:
```typescript
export async function openCustomerPortal(): Promise<responseAction> {
const session = await auth();
if (!session?.user?.id) throw new Error("Unauthorized");
const user = await prisma.user.findUnique({
where: { id: session.user.id },
select: { stripeCustomerId: true },
});
if (!user?.stripeCustomerId) throw new Error("No subscription found");
const stripeSession = await stripe.billingPortal.sessions.create({
customer: user.stripeCustomerId,
return_url: billingUrl,
});
redirect(stripeSession.url);
} |
|---|
| उपयोगकर्ता | Ghufran Khan (UID 95493) |
|---|
| सबमिशन | 07/03/2026 06:06 PM (1 महीना पहले) |
|---|
| संयम | 21/03/2026 05:49 PM (14 days later) |
|---|
| स्थिति | स्वीकृत |
|---|
| VulDB प्रविष्टि | 352376 [mickasmt next-saas-stripe-starter 1.0.0 Stripe API open-customer-portal.ts openCustomerPortal अधिकार वृद्धि] |
|---|
| अंक | 17 |
|---|