{"id":"stripe-webhook-verify-and-parse","version":"1.0.0","primitive":"code_execution","description":"Webhook signing secret from Stripe dashboard (whsec_...)","registry_refs":["stripe"],"tags":[],"solves":[],"auth_required":true,"verified":false,"last_verified":"null","next_check":"2026-07-30","eval_result":"null","eval_env":"null","mast":[],"ref":"https://arxiv.org/abs/2503.13657","inputs":[{"name":"STRIPE_SECRET_KEY","required":true,"description":"Stripe secret key (sk_test_... for test mode)"},{"name":"STRIPE_WEBHOOK_SECRET","required":true,"description":"Webhook signing secret from Stripe dashboard (whsec_...)"}],"executable":"# ============================================\n# checklist:     stripe-webhook-verify-and-parse\n# version:       1.0.0\n# primitive:     code_execution\n# description:   Verify a Stripe webhook signature and parse the event payload safely\n# registry_refs: stripe\n# auth_required: true\n# verified:      false\n# last_verified: null\n# next_check:    2026-07-30\n# eval_result:   null\n# eval_env:      null\n#\n# inputs:\n#   - name: STRIPE_SECRET_KEY\n#     required: true\n#     description: Stripe secret key (sk_test_... for test mode)\n#   - name: STRIPE_WEBHOOK_SECRET\n#     required: true\n#     description: Webhook signing secret from Stripe dashboard (whsec_...)\n#\n# OUTPUTS:\n#   valid_sig_ok     — true if valid signature verified correctly\n#   invalid_sig_blocked — true if tampered payload was rejected\n#   event_type       — parsed event type from valid payload\n#\n# MAST FAILURE MODES ADDRESSED:\n# FM-1.1 Disobey Task Specification        — raw bytes used for verification, not parsed JSON\n# FM-2.4 Information Withholding           — SignatureVerificationError surfaced explicitly\n# FM-3.3 Incorrect Verification            — tampered payload tested to confirm rejection\n#\n# ref: https://arxiv.org/abs/2503.13657\n# ============================================\n\nimport sys\nimport os\nimport subprocess\nimport time\nimport urllib.request\nimport json\n\n# ─────────────────────────────────────────\n# PRE_EXECUTION\n# ─────────────────────────────────────────\n\nfor attempt in range(2):\n    try:\n        req = urllib.request.Request(\n            \"https://checklist.day/api/registry/stripe\",\n            headers={\"User-Agent\": \"checklist-agent/1.0\"}\n        )\n        with urllib.request.urlopen(req, timeout=10) as resp:\n            registry = json.loads(resp.read())\n            break\n    except Exception as e:\n        if attempt == 1:\n            print(f\"ABORT: registry unreachable — {e}\")\n            sys.exit(1)\n        time.sleep(2)\n\nwarnings = registry.get(\"warnings\", [])\nif warnings:\n    print(\"[stripe] WARNINGS:\")\n    for w in warnings if isinstance(warnings, list) else [warnings]:\n        print(f\"  ⚠ {w}\")\n\n# ─────────────────────────────────────────\n# EXECUTION\n# ─────────────────────────────────────────\n\nsubprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", \"stripe>=7.0.0\"])\n\nimport stripe\nSignatureVerificationError = stripe.SignatureVerificationError\n\nSTRIPE_SECRET_KEY     = os.environ.get(\"STRIPE_SECRET_KEY\")\nSTRIPE_WEBHOOK_SECRET = os.environ.get(\"STRIPE_WEBHOOK_SECRET\")\n\nif not STRIPE_SECRET_KEY:\n    print(\"ABORT: STRIPE_SECRET_KEY not set\"); sys.exit(1)\nif not STRIPE_SECRET_KEY.startswith(\"sk_test_\"):\n    print(\"ABORT: use test mode key\"); sys.exit(1)\nif not STRIPE_WEBHOOK_SECRET:\n    print(\"ABORT: STRIPE_WEBHOOK_SECRET not set (whsec_...)\"); sys.exit(1)\n\nstripe.api_key = STRIPE_SECRET_KEY\n\n# Build a realistic webhook payload\nts        = int(time.time())\npayload   = json.dumps({\n    \"id\":      f\"evt_test_{ts}\",\n    \"type\":    \"payment_intent.succeeded\",\n    \"object\":  \"event\",\n    \"data\":    {\"object\": {\"id\": \"pi_test\", \"amount\": 2000, \"currency\": \"usd\"}},\n    \"created\": ts,\n}).encode(\"utf-8\")\n\n# Generate valid signature\n# FOOTGUN: Stripe signs the raw bytes, not the parsed JSON — never re-serialize before verifying\nsigned_header = stripe.WebhookSignature._compute_signature(\n    f\"{ts}.{payload.decode()}\", STRIPE_WEBHOOK_SECRET\n)\nvalid_header = f\"t={ts},v1={signed_header}\"\n\n# 1. Verify valid signature\nvalid_sig_ok = False\nevent_type   = None\ntry:\n    event        = stripe.Webhook.construct_event(payload, valid_header, STRIPE_WEBHOOK_SECRET)\n    valid_sig_ok = True\n    event_type   = event[\"type\"]\n    print(f\"  valid signature: OK — event type={event_type}\")\nexcept SignatureVerificationError as e:\n    print(f\"  FAIL: valid sig rejected — {e}\")\n\n# 2. Verify tampered payload is rejected\n# FOOTGUN: never trust payload without verifying signature first\ninvalid_sig_blocked = False\ntampered_payload    = payload + b\" tampered\"\ntry:\n    stripe.Webhook.construct_event(tampered_payload, valid_header, STRIPE_WEBHOOK_SECRET)\n    print(f\"  FAIL: tampered payload was accepted (should have been rejected)\")\nexcept SignatureVerificationError:\n    invalid_sig_blocked = True\n    print(f\"  tampered payload rejected: OK\")\n\n# ─────────────────────────────────────────\n# POST_EXECUTION\n# ─────────────────────────────────────────\n\nassert valid_sig_ok, \"FAIL: valid signature was rejected\"\nassert invalid_sig_blocked, \"FAIL: tampered payload was not rejected\"\nassert event_type == \"payment_intent.succeeded\", f\"FAIL: unexpected event type {event_type}\"\n\nresult = {\n    \"valid_sig_ok\":        valid_sig_ok,\n    \"invalid_sig_blocked\": invalid_sig_blocked,\n    \"event_type\":          event_type,\n}\nprint(json.dumps(result, indent=2))\nprint(\"PASS\")\n"}