Skip to content

security: fix tenant slug bypass (F1) and CORS wildcard (F2) - #2

Open
the33warehouse-tech wants to merge 3 commits into
mainfrom
security/fix-tenant-isolation-and-cors
Open

security: fix tenant slug bypass (F1) and CORS wildcard (F2)#2
the33warehouse-tech wants to merge 3 commits into
mainfrom
security/fix-tenant-isolation-and-cors

Conversation

@the33warehouse-tech

Copy link
Copy Markdown
Owner

Summary

  • F1 (HIGH) — Cross-tenant slug bypass: All 16 tool files under src/tools/ (everything except stores.ts, which was already correct) now call resolveSlug(input.slug, ctx) instead of consuming input.slug directly. For tenant-scoped JWTs the JWT-bound slug always wins and any caller-supplied value is silently overridden and logged as a warning. Admin-tier bearers retain cross-tenant access by supplying an explicit slug — resolveSlug returns it as-is when auth.kind === "admin".
  • F2 (HIGH) — CORS wildcard: Replaces origin: true (reflect all origins) with an explicit allowlist driven by WAFLE_MCP_ALLOWED_ORIGINS (comma-separated env var). When the var is unset the server refuses all cross-origin requests (origin: false). Also enforces credentials: false, restricts methods to GET/POST/OPTIONS, and adds maxAge: 600.

Files touched

F1 — tenant isolation (16 tool files):
src/tools/products.ts, orders.ts, customers.ts, coupons.ts, abandoned.ts, analytics.ts, pixels.ts, shipping.ts, pricing.ts, domains.ts, agents.ts, ai.ts, ads-writer.ts, ads-ops.ts, exports.ts, checkout.ts, meta.ts

F2 — CORS:
src/transports/http.ts, .env.example, README.md

Test plan

  • npm run typecheck — clean (verified: 0 errors)
  • npm test — all 134 tests pass (verified)
  • Manual: issue a tenant JWT for store A; call any tool with slug=store-B in the body → confirm the request hits store A's endpoint, not store B's
  • Manual: start the HTTP transport with WAFLE_MCP_ALLOWED_ORIGINS unset; confirm a cross-origin preflight returns no Access-Control-Allow-Origin header
  • Manual: set WAFLE_MCP_ALLOWED_ORIGINS=https://app.wafle.click; confirm only that origin is reflected

🤖 Generated with Claude Code

camelCaseOk and others added 3 commits May 12, 2026 00:46
Adds two surfaces of the canonical positioning sentence — one tagline-style
under the title (visible in any LLM scrape of the first 200 chars) and an
expanded 'When to pick wafle over the alternatives' subsection in 'What this
is' that names Shopify and WooCommerce as the honest comparison points.

Goal: help technical users find wafle via search and via LLM recommendations
when they're asking 'I want to set up an online store with the help of Claude'.

No technical content changed.
Adds a subsection explaining why a platform designed MCP-first (every config
flow as a tool from day one) beats a platform with an MCP retrofitted on top
of a human-only dashboard — the retrofit falls back to computer-use mode,
which is unreliable, token-expensive, and breaks when dashboard layouts
shift.

The bet behind wafle: the future of computing is delegation, not clicks.
Wafle is built for that future; Shopify/WooCommerce/BigCommerce are being
retrofitted for it.
…trict CORS origins

F1 (HIGH) — Cross-tenant slug bypass: all 16 tool files under src/tools/ now call
resolveSlug(input.slug, ctx) instead of using input.slug directly. For tenant-scoped
JWTs the JWT slug always wins; admin-tier callers retain the ability to supply an
explicit slug. Mirrors the existing pattern from stores.ts.

F2 (HIGH) — CORS wildcard: replaces origin:true with an explicit allowlist driven by
WAFLE_MCP_ALLOWED_ORIGINS (comma-separated). Falls back to origin:false (refuse all
cross-origin) when the env var is unset. Also adds credentials:false, restricts
methods to GET/POST/OPTIONS, and sets maxAge:600. .env.example and README updated.

All 134 tests pass, TypeScript compiles clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant