T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- auth-middleware.js:74
- Finding
- Spoofable User Identity and Fail-Open License Authorization<![CDATA[ ## Vulnerability Details **File Location**: `auth-middleware.js:74-89`, `auth-middleware.js:175-205`, and `auth-middleware.js:224-233` **Vulnerability Type**: Authentication bypass and fail-open authorization **Risk Level**: High ### Vulnerable Code ```javascript async function getUserLicense(email) { if (!email) return { tier: 'FREE', features: {} }; // 1. Cache hit const cached = getCachedLicense(email); if (cached) return cached; // 2. Webhook lookup try { const license = await httpGet(`${PROCU_WEBHOOK_URL}/license?email=${encodeURIComponent(email)}`); setCachedLicense(email, license); return license; } catch (err) { // 3. Webhook unreachable → dev/fallback mode using env var console.warn(`[Auth] Webhook unreachable (${err.message}) — using PROCU_ALLOWED_TIER=${PROCU_ALLOWED_TIER}`); return { tier: PROCU_ALLOWED_TIER, features: getFeaturesForTier(PROCU_ALLOWED_TIER) }; } } ``` ```javascript function authorizeSync(email, feature) { if (!email) { const err = new Error(`Error: This feature requires an Enterprise License. [${feature}]`); err.code = 'LICENSE_DENIED'; err.requiredFeature = feature; err.userTier = 'FREE'; throw err; } const cached = getCachedLicense(email); if (cached) { const allowed = cached.features && cached.features[feature]; if (!allowed) { const err = new Error(`Error: This feature requires an Enterprise License. [${feature}]`); err.code = 'LICENSE_DENIED'; err.requiredFeature = feature; err.userTier = cached.tier || 'FREE'; throw err; } return cached; } // Cache miss in sync context — use env fallback (do NOT block) // Caller should use authorize() for production async contexts const tier = PROCU_ALLOWED_TIER; const features = getFeaturesForTier(tier); const allowed = features[feature]; if (!allowed) { const err = new Error(`Error: This feature requires an Enterprise License. [${feature}]`); ...[truncated 2970 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace email-based identity assertions with signed, expiring authentication tokens issued by a trusted identity provider. 2. Validate token signatures, issuer, audience, expiry, and subject before performing a license lookup. 3. Derive the license email or customer ID from verified token claims rather than query parameters. 4. Remove support for base64-encoded emails as bearer credentials. 5. Fail closed when the license service is unavailable in production. 6. Remove `PROCU_ALLOWED_TIER` from production authorization paths. If a development bypass is required: - Require an explicit development mode. - Refuse to start if the bypass is enabled in production. - Bind development services to localhost. - Emit a prominent startup warning. 7. Avoid `authorizeSync()` for security-sensitive operations. Use the asynchronous verifier and require a successful authoritative lookup or a cryptographically protected cache entry. 8. Add tests covering forged emails, malformed bearer values, license-service outages, cache misses, and privileged fallback configurations. ]]>
