davila7/claude-code-templates · warning
Cross-origin request rejected
Error message
Cross-origin request rejected
What it means
HTTP 403 from the sandbox-server CORS middleware: any request carrying an Origin header not in the ALLOWED_ORIGINS set is rejected before reaching the state-changing endpoints. This is deliberate CSRF-style protection for a local sandbox server.
Source
Thrown at cli-tool/src/sandbox-server.js:74
// CORS middleware — restrict to the local Studio UI origin only.
// A wildcard (`*`) origin combined with the command-executing endpoints below
// lets any web page the developer visits drive requests into this server
// (drive-by RCE). Only allow the same-origin UI served from localhost:PORT.
const ALLOWED_ORIGINS = new Set([
`http://localhost:${PORT}`,
`http://127.0.0.1:${PORT}`,
]);
app.use((req, res, next) => {
const origin = req.headers.origin;
if (origin && ALLOWED_ORIGINS.has(origin)) {
res.header('Access-Control-Allow-Origin', origin);
}
res.header('Vary', 'Origin');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
// Reject cross-origin requests outright for the state-changing endpoints.
if (origin && !ALLOWED_ORIGINS.has(origin)) {
return res.status(403).json({ success: false, error: 'Cross-origin request rejected' });
}
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
// JSON parsing middleware
app.use(express.json());
// Store active tasks
const activeTasks = new Map();
// Serve the sandbox interface at root
app.get('/', (req, res) => {
// Try local file first (when running from npm package)
const localPath = path.join(__dirname, 'sandbox-interface.html');View on GitHub (pinned to a0851ed10c)
Solutions
- Serve your client from an origin that's in ALLOWED_ORIGINS (check sandbox-server.js for the set) or add your exact origin (scheme+host+port) to it
- Use http://localhost:PORT consistently rather than mixing 127.0.0.1 and localhost
- If calling from Node/curl (no Origin header), the check is skipped — use a non-browser client for scripting
- Confirm you're not accidentally embedding the sandbox URL in an external web page
Example fix
// before // client served at http://localhost:5173, only localhost:3000 allowed -> 403 // after (sandbox-server.js) const ALLOWED_ORIGINS = new Set(['http://localhost:3000', 'http://localhost:5173']);
Defensive patterns
Strategy: validation
Validate before calling
const allowed = new Set(['http://localhost:3000']); // mirror server set
if (typeof window !== 'undefined' && !allowed.has(window.location.origin)) {
console.warn('requests to sandbox server will be rejected from', window.location.origin);
} Try / catch
catch (e) { if (e.status === 403 && /Cross-origin/.test(e.message)) showOriginHint(); else throw e; } Prevention
- Serve the UI and the sandbox server from the same origin/port
- Pick one hostname (localhost) and stick to it
- Keep the ALLOWED_ORIGINS set in sync with every port you develop on
When it happens
Trigger: A browser page on a non-allowed origin (e.g. an open port on localhost with a different port number, or a public website) makes a fetch to the sandbox server with credentials/content-type that attach an Origin header, and that origin isn't in ALLOWED_ORIGINS.
Common situations: Serving your frontend on a different port than the one allow-listed (localhost:3000 vs localhost:5173); accessing via 127.0.0.1 when only localhost is allowed (they are distinct origins); a malicious or accidental cross-site request from a web page you have open.
Related errors
AI-assisted analysis of davila7/claude-code-templates@a0851ed10c (2026-08-28).
Data as JSON: /api/errors/fff4b5482128fa0f.
Report an issue: GitHub.