Skip to content

fix: allow vercel preview builds to access the local connector#1794

Closed
neutrino2211 wants to merge 1 commit intonpmx-dev:mainfrom
neutrino2211:fix/allow-vercel-connector-access
Closed

fix: allow vercel preview builds to access the local connector#1794
neutrino2211 wants to merge 1 commit intonpmx-dev:mainfrom
neutrino2211:fix/allow-vercel-connector-access

Conversation

@neutrino2211
Copy link
Copy Markdown
Contributor

🔗 Linked issue

#1793

🧭 Context

The CLI connector uses CORS headers to secure access to it, the headers however do not allow access from vercel preview deployments.

📚 Description

This PR adds the following regex to allowed origins

/^https:\/\/(.*)\.vercel\.app$/

Regex itself might need some work 😬

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Mar 1, 2026 5:34pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Mar 1, 2026 5:34pm
npmx-lunaria Ignored Ignored Mar 1, 2026 5:34pm

Request Review

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 1, 2026

📝 Walkthrough

Walkthrough

The pull request extends the CORS origin allowlist in the CLI server configuration to include a regex pattern permitting any Vercel app domain matching https://*.vercel.app. This addition supplements the existing permitted origins for npmx.dev and localhost environments. The change modifies only the CORS configuration without altering underlying logic or error handling mechanisms.

Possibly related issues

🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly relates to the changeset, explaining the addition of a Vercel regex pattern to CORS allowed origins.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2215a36 and ff0390d.

📒 Files selected for processing (1)
  • cli/src/server.ts

Comment thread cli/src/server.ts
'https://npmx.dev',
/^http:\/\/localhost:\d+$/,
/^http:\/\/127.0.0.1:\d+$/,
/^https:\/\/(.*)\.vercel\.app$/,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

head -120 cli/src/server.ts | tail -40

Repository: npmx-dev/npmx.dev

Length of output: 1044


🏁 Script executed:

find . -name "vercel.json" -o -name ".vercelignore" | head -5

Repository: npmx-dev/npmx.dev

Length of output: 74


🏁 Script executed:

grep -n "vercel" package.json | head -10

Repository: npmx-dev/npmx.dev

Length of output: 43


🌐 Web query:

Vercel preview deployment URL pattern subdomain structure and how to scope CORS to specific projects or teams

💡 Result:

Vercel preview deployment URL patterns (default .vercel.app)

Vercel “generated URLs” are built from these components: <project-name>, <scope-slug> (team/account slug), optional <branch-name>, and optional <unique-hash>. (vercel.com)

Common preview URL structures from Git: (vercel.com)

  • Commit-specific preview (changes for one commit):
    https://<project-name>-<unique-hash>-<scope-slug>.vercel.app
  • Branch preview (always latest for that branch):
    https://<project-name>-git-<branch-name>-<scope-slug>.vercel.app

(There are also CLI-generated forms like https://<project-name>-<scope-slug>.vercel.app and sometimes ...-<author-name>-... for team deployments.) (vercel.com)

Making preview URLs predictable (best for CORS allowlists)

If you need a stable domain pattern, use Preview Deployment Suffix to replace .vercel.app with a domain you control (configured at the team level, and the domain must exist/be active in that team). (vercel.com)
Example outcome: previews become something like https://<project>...<team>.<your-preview-suffix-domain> instead of ...vercel.app. (vercel.com)

If you want wildcard-style origins (e.g. https://*.preview.example.com), you typically pair this with Vercel-managed DNS / wildcard domain handling so subdomains resolve cleanly. (vercel.com)

How to scope CORS to specific Vercel projects/teams

CORS itself doesn’t understand “Vercel project/team”—it only sees the request Origin (scheme + host + port). So you scope by matching the Origin host to the project/team patterns you allow.

Option A (works with default .vercel.app): validate origin by suffix + project prefix

Use a dynamic origin check on your API:

  • Require host ends with: -<scope-slug>.vercel.app (scopes to one team/account)
  • Also require host starts with: <project-name>- (scopes to one project)
  • Optionally allow only the -git- (branch) form and/or the -<unique-hash>- (commit) form. (vercel.com)

Example (Node/Next API-style logic):

const allowedScope = "my-team-slug";
const allowedProject = "my-project";

function isAllowedVercelPreviewOrigin(origin) {
  try {
    const { protocol, hostname } = new URL(origin);
    if (protocol !== "https:") return false;

    // team/account scope
    if (!hostname.endsWith(`-${allowedScope}.vercel.app`)) return false;

    // project scope
    if (!hostname.startsWith(`${allowedProject}-`)) return false;

    // optional: ensure it matches either branch or commit style
    const ok =
      hostname.includes(`-git-`) || /-[0-9a-z]{9}-/.test(hostname); // "unique-hash" is 9 chars
    return ok;
  } catch {
    return false;
  }
}

(That 9-character “unique-hash” length is documented.) (vercel.com)

Option B (recommended for strict allowlists): use a custom Preview Deployment Suffix domain per team

With a suffix like preview.example.com, you can allow:

  • https://*.preview.example.com (broad to that team’s preview domain), or
  • https://<project-pattern>.preview.example.com (narrower), depending on how your generated hostnames look after the suffix change. (vercel.com)

Option C: if Deployment Protection breaks CORS preflights

If your previews are protected (Vercel Authentication / Password / Trusted IPs), browser OPTIONS preflights can be blocked. Vercel documents using OPTIONS Allowlist so preflights can succeed (commonly for /api/*) while keeping real requests protected. (vercel.com)

If you tell me your team slug, project name, and whether you’re using default .vercel.app vs Preview Deployment Suffix, I can give you an exact regex/implementation (and for which environments: preview only vs preview+prod).

Citations:


🏁 Script executed:

cat vercel.json | jq . 2>/dev/null || cat vercel.json

Repository: npmx-dev/npmx.dev

Length of output: 2099


🏁 Script executed:

rg -i "team|scope|slug" --type json --type ts -C 2 | head -30

Repository: npmx-dev/npmx.dev

Length of output: 1796


Scope the Vercel CORS origin pattern to your team's deployments.

The regex /^https:\/\/(.*)\.vercel\.app$/ allows CORS requests from any Vercel deployment (across all users and teams). Whilst token validation provides secondary protection, CORS should still follow the defence-in-depth principle.

Vercel preview URLs include the team/account scope slug. Scope your pattern to match your deployments only:

/^https:\/\/npmx-dev-.*-<your-team-slug>\.vercel\.app$/

Replace <your-team-slug> with your Vercel team's slug (visible in your team settings or Vercel preview URLs). This ensures only your team's deployments can request CORS access, not arbitrary Vercel apps from other users or organisations.

@danielroe
Copy link
Copy Markdown
Member

I deliberately did not do this as it allows any person to create a spoof of npmx that can access the connector (in other words, we might as well not even have CORS origins). having a reviewer run the preview build locally is an acceptable tradeoff for the better security.

@neutrino2211
Copy link
Copy Markdown
Contributor Author

Okay, that makes sense. Should have waited for clarification before opening PR, my apologies.

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.

2 participants