T09 · Insecure Skill Coding Practices
- Location
scripts/stripe_helpers.py:134- Finding
Webhook events are dispatched without persistent idempotency protection
- Content
View full analysis
str: """ Dispatch a Stripe webhook event to the correct handler. Args: event: Parsed event dict from verify_webhook(). handlers: Dict mapping event type → callable(data). e.g. { "checkout.session.completed": my_checkout_handler, "customer.subscription.deleted": my_cancel_handler, } Returns: "handled" if a matching handler was called, "ignored" otherwise. """ event_type = event.get("type", "") data = event.get("data", {}).get("object", {}) handler = handlers.get(event_type) if handler: handler(data) return "handled" return "ignored" ``` The documentation proposes an optional in-memory mechanism, but it is not integrated into the webhook handler: ```python PROCESSED_EVENTS = set() def is_duplicate_event(event_id: str) -> bool: if event_id in PROCESSED_EVENTS: return True PROCESSED_EVENTS.add(event_id) return False ``` ### Technical Analysis Stripe retries webhook deliveries when acknowledgements are delayed, lost, or return an error. A valid event may therefore be delivered more than once. The reusable dispatcher immediately invokes the business handler without checking whether `event["id"]` has already been processed. The example in `SKILL.md` does not resolve this issue because its duplicate-event check is only presented as optional commented guidance. Its process-local `set` would also be insufficient in production: it is lost during restarts and is not shared across application workers or servers. A check followed by a separate insertion can also be su ...[truncated 1390 chars]- Remediation
View remediation
