@carrierllc/mcp 0.2.18 → 0.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@
17
17
  "clsx": "^2.1.1",
18
18
  "framer-motion": "^11.15.0",
19
19
  "geist": "^1.3.1",
20
- "next": "^15.3.0",
20
+ "next": "^16.3.0",
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0",
23
23
  "tailwind-merge": "^2.6.0"
@@ -29,8 +29,8 @@
29
29
  "@types/node": "^22.0.0",
30
30
  "@types/react": "^19.0.0",
31
31
  "@types/react-dom": "^19.0.0",
32
- "eslint": "^9.0.0",
33
- "eslint-config-next": "^15.3.0",
32
+ "eslint": "^10.8.1",
33
+ "eslint-config-next": "^16.3.0",
34
34
  "tailwindcss": "^4.1.4",
35
35
  "typescript": "^5.8.0",
36
36
  "wrangler": "^4.94.0"
@@ -7,11 +7,23 @@ type StripeSession = {
7
7
  customer_details?: { email?: string | null };
8
8
  };
9
9
 
10
+ /** See verify-checkout-session.ts — same charset gate for path interpolation. */
11
+ const STRIPE_SESSION_ID_RE = /^[A-Za-z0-9_-]{1,256}$/;
12
+
13
+ function safeStripeSessionId(sessionId: string): string | null {
14
+ if (typeof sessionId !== "string" || !STRIPE_SESSION_ID_RE.test(sessionId)) {
15
+ return null;
16
+ }
17
+ return encodeURIComponent(sessionId);
18
+ }
19
+
10
20
  async function fetchStripeSession(sessionId: string): Promise<StripeSession | null> {
11
21
  const stripeKey = process.env.STRIPE_SECRET_KEY;
12
22
  if (!stripeKey) return null;
23
+ const safeSessionId = safeStripeSessionId(sessionId);
24
+ if (!safeSessionId) return null;
13
25
 
14
- const resp = await fetch(`https://api.stripe.com/v1/checkout/sessions/${sessionId}`, {
26
+ const resp = await fetch(`https://api.stripe.com/v1/checkout/sessions/${safeSessionId}`, {
15
27
  headers: { Authorization: `Bearer ${stripeKey}` },
16
28
  });
17
29
  if (!resp.ok) return null;
@@ -21,12 +33,14 @@ async function fetchStripeSession(sessionId: string): Promise<StripeSession | nu
21
33
  async function setStripeClaimedBy(sessionId: string, userId: string): Promise<boolean> {
22
34
  const stripeKey = process.env.STRIPE_SECRET_KEY;
23
35
  if (!stripeKey) return false;
36
+ const safeSessionId = safeStripeSessionId(sessionId);
37
+ if (!safeSessionId) return false;
24
38
 
25
39
  const formBody = new URLSearchParams({
26
40
  "metadata[claimedByUserId]": userId,
27
41
  });
28
42
 
29
- const resp = await fetch(`https://api.stripe.com/v1/checkout/sessions/${sessionId}`, {
43
+ const resp = await fetch(`https://api.stripe.com/v1/checkout/sessions/${safeSessionId}`, {
30
44
  method: "POST",
31
45
  headers: {
32
46
  Authorization: `Bearer ${stripeKey}`,
@@ -12,6 +12,22 @@ type VerifyResult =
12
12
  | { ok: true; orderId: string; purchaserEmail: string | null }
13
13
  | { ok: false };
14
14
 
15
+ /**
16
+ * Stripe Checkout session ids are opaque tokens (`cs_test_…` / `cs_live_…`).
17
+ * They are interpolated into the Stripe API URL, so an unvalidated value can
18
+ * inject `?`/`#`/`../` and retarget the request *with the Stripe secret key
19
+ * attached* (CodeQL js/request-forgery). Restrict to an explicit charset and
20
+ * encode before interpolation.
21
+ */
22
+ const STRIPE_SESSION_ID_RE = /^[A-Za-z0-9_-]{1,256}$/;
23
+
24
+ function safeStripeSessionId(sessionId: string): string | null {
25
+ if (typeof sessionId !== "string" || !STRIPE_SESSION_ID_RE.test(sessionId)) {
26
+ return null;
27
+ }
28
+ return encodeURIComponent(sessionId);
29
+ }
30
+
15
31
  /**
16
32
  * Confirms a Stripe Checkout session is paid before allowing post-payment flows.
17
33
  * Mock sessions are only accepted when Stripe is not configured (local/dev builds).
@@ -27,7 +43,8 @@ export async function verifyCheckoutSession(
27
43
  return { ok: true, orderId: templateId, purchaserEmail: null };
28
44
  }
29
45
 
30
- if (!sessionId) {
46
+ const safeSessionId = safeStripeSessionId(sessionId);
47
+ if (!safeSessionId) {
31
48
  return { ok: false };
32
49
  }
33
50
 
@@ -36,7 +53,7 @@ export async function verifyCheckoutSession(
36
53
  return { ok: false };
37
54
  }
38
55
 
39
- const resp = await fetch(`https://api.stripe.com/v1/checkout/sessions/${sessionId}`, {
56
+ const resp = await fetch(`https://api.stripe.com/v1/checkout/sessions/${safeSessionId}`, {
40
57
  headers: { Authorization: `Bearer ${stripeKey}` },
41
58
  });
42
59