T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/soundstudiopro.com/private_html/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/private_html/SUBSCRIBE_AUDIT.md
# Subscribe.php Audit Report

## 🔍 Current Flow Analysis

### Question: Does subscription get created with Stripe every time user clicks subscribe?

**Answer: YES** - A Stripe Checkout Session is created every time the user clicks the subscribe button (if they don't have an active subscription).

### Current Flow:

1. **Page Load (GET request)**:
   - Line 121: Checks for existing subscription ONCE: `$existing_subscription = hasActiveSubscription($_SESSION['user_id']);`
   - Displays subscription info if exists, or shows subscribe button if not

2. **Button Click (POST request)**:
   - Line 126: `if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_subscription']))`
   - Line 128: Checks `$existing_subscription` (from page load, not fresh check!)
   - Line 187-197: Creates NEW Stripe Checkout Session every time
   - Redirects to Stripe Checkout

## ⚠️ Issues Found

### 1. **RACE CONDITION - Stale Subscription Check**
**Location:** Lines 121, 128

**Problem:**
- Subscription check happens at page load (line 121)
- When user clicks subscribe, it uses the OLD check result (line 128)
- If user subscribes in another tab/window between page load and button click, the check won't catch it

**Impact:** User could create duplicate subscriptions

**Fix Needed:** Check subscription status INSIDE the POST handler, not before

### 2. **NO RATE LIMITING**
**Location:** Line 187

**Problem:**
- No protection against rapid button clicks
- User could spam-click and create multiple checkout sessions
- Each checkout session creation costs API quota

**Impact:** 
- Multiple Stripe API calls
- Potential for duplicate checkout sessions
- Poor user experience

**Fix Needed:** Add rate limiting or disable button after first click

### 3. **NO DUPLICATE CHECKOUT SESSION PREVENTION**
**Location:** Line 187-197

**Problem:**
- No check for existing pending checkout sessions
- User could have multiple active checkout sessions for same plan

**Impact:** Confusion, potential duplicate charges

**Fix Needed:** Check for existing pending sessions before creating new one

### 4. **NO CSRF PROTECTION**
**Location:** Line 349 (form)

**Problem:**
- Form has no CSRF token
- Vulnerable to CSRF attacks

**Impact:** Security vulnerability

**Fix Needed:** Add CSRF token to form

### 5. **HARDCODED STRIPE SECRET KEY**
**Location:** Line 123

**Problem:**
- Stripe secret key is hardcoded in the file
- Should be in environment variable or config file

**Impact:** Security risk if file is exposed

**Fix Needed:** Move to environment variable

## ✅ What Works Correctly

1. ✅ Checks for active subscription before showing subscribe button
2. ✅ Validates price ID configuration
3. ✅ Proper error handling for Stripe API calls
4. ✅ Redirects to Stripe Checkout correctly
5. ✅ Uses metadata to track user_id and plan

## 🔧 Recommended Fixes

### Priority 1: Fix Race Condition
```php
// Inside POST handler, check subscription status FRESH
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_subscription'])) {
    // FRESH check for existing subscription
    $existing_subscription = hasActiveSubscription($_SESSION['user_id']);
    
    if ($existing_subscription && is_array($existing_subscription)) {
        // Block subscription
    }
}
```

### Priority 2: Add Rate Limiting
```php
// Check if user recently created a checkout session
$recent_session_stmt = $pdo->prepare("
    SELECT id FROM checkout_sessions 
    WHERE user_id = ? 
    AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
    LIMIT 1
");
$recent_session_stmt->execute([$_SESSION['user_id']]);
if ($recent_session_stmt->fetch()) {
    $error_message = "Please wait a moment before creating another checkout session.";
}
```

### Priority 3: Disable Button After Click
```javascript
// Add to form button
onclick="this.disabled=true; this.form.submit();"
```

### Priority 4: Add CSRF Protection
```php
// Generate token
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));

// In form
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">

// In POST handler
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die("Invalid request");
}
```

### Priority 5: Move Stripe Secret to Config
```php
$stripe_secret = getenv('STRIPE_SECRET_KEY') 
    ?? require __DIR__ . '/config/stripe.php';
```

## 📊 Summary

**Current Behavior:**
- ✅ Creates Stripe Checkout Session on each click (correct)
- ❌ Uses stale subscription check (race condition)
- ❌ No rate limiting (can spam-click)
- ❌ No CSRF protection (security risk)
- ❌ Hardcoded secret key (security risk)

**Recommendation:**
Fix the race condition first (Priority 1), then add rate limiting (Priority 2), then security improvements (Priorities 3-5).


CasperSecurity Mini