T09 · Insecure Skill Coding Practices
- Location
scripts/payment_handler.py:33- Finding
Process-Global Stripe API Key Causes Cross-Instance Credential Confusion
- Content
View full analysis
Vulnerability Details
File Location:
scripts/payment_handler.py:33-39, with global-key API use atscripts/payment_handler.py:77-83andscripts/payment_handler.py:205-210
Vulnerability Type: Shared global credential state
Risk Level: HighVulnerable Code
python # Initialize Stripe if stripe_key: stripe.api_key = stripe_key self.stripe_enabled = True else: self.stripe_enabled = FalseStripe operations are subsequently performed without passing an instance-specific key:
python intent = stripe.PaymentIntent.create( amount=int(amount * 100), currency=currency.lower(), description=description, metadata=metadata or {} )python refund_data = {"payment_intent": payment_intent_id} if amount: refund_data["amount"] = int(amount * 100) refund = stripe.Refund.create(**refund_data)Technical Analysis
Each
PaymentHandlerstoresself.stripe_key, but initialization also assigns that credential to the process-globalstripe.api_key. Stripe requests do not useself.stripe_key; they use whichever credential was most recently assigned globally.In an application with multiple merchants, tenants, tests, background jobs, or concurrently initialized handlers, constructing one handler silently changes the credentials used by every other handler in the process. A handler that appears to represent merchant A can therefore create payments or attempt refunds through merchant B's Stripe account.
This violates tenant isolation and can produce credential races under concurrent execution.
Attack Path
- A service creates
PaymentHandler(stripe_key=key_for_merchant_a). - Another tenant or worker creates
PaymentHandler(stripe_key=key_for_merchant_b). - The second initialization overwrites the global
stripe.api_key. - The first handler calls
create_stripe_order()orrefund_stripe_order(). - Stripe receives the ...[truncated 740 chars]
- A service creates
- Remediation
View remediation
Remediation Suggestions
-
Do not assign tenant credentials to
stripe.api_key. -
Use a request-scoped Stripe client or pass the API key explicitly for every request. With supported Stripe SDK versions, prefer
StripeClient:python from stripe import StripeClient self.stripe_client = StripeClient(stripe_key) intent = self.stripe_client.v1.payment_intents.create({...}) -
If compatibility requires static resource methods, pass
api_key=self.stripe_keyon every call rather than relying on global state. -
Validate that each payment or refund belongs to the authenticated merchant before issuing an operation.
-
Add concurrent and multi-tenant tests that initialize handlers with different keys and assert that each outgoing request uses the correct credential.
-
Use restricted Stripe keys containing only the permissions required by this toolkit.
-
