Pascal Editor
Pascal MCP security: loopback, shared token and scene-write boundaries
Inspect HTTP guards, origin handling, request limits and versioned writes without confusing transport authentication with tenant isolation or safe geometry.
What you will learn
- The managed token protects a local service boundary
- Origin policy and rate limits have specific scope
- Protect data mutations and imported content separately
Before you start
- Basic scene-graph, JavaScript and HTTP concepts
- An owned small scene with expected dimensions and relationships
Explain the implementation boundary and reproduce the chapter’s checklist or narrow graph exercise.
Key takeaways
- A shared MCP token is not tenant authorization.
- Origins, request caps and protocol sessions have distinct scopes.
- Version checks prevent stale writes, not unauthorized writes.
The managed token protects a local service boundary
The CLI generates a 32-byte random token, writes it with requested mode 0600 and passes it to the MCP process. The connector reads that token and attaches it to its HTTP transport. File-mode requests still need verification on the target operating system; do not claim that one numeric mode proves equivalent access controls on every platform.
connectHttp defaults to loopback and rejects non-loopback binding without an authentication token. When a token is configured, the guard checks bearer or the alternate Pascal token header using equal-length buffers and timingSafeEqual. The health endpoint passes through the guard too. A valid shared service token is not a per-user tenant authorization scheme.
Origin policy and rate limits have specific scope
The guard checks a supplied Origin, applies CORS and handles OPTIONS before token verification. Loopback origins, matching request-host origins and configured origins can be accepted. That is broader than saying only one exact configured origin is allowed. Requests without Origin still need the configured token, and browser origin policy must not be described as authentication for non-browser clients.
The default request cap is 120 per minute for /mcp, keyed by the socket’s remote address. It is not a per-tool budget or a per-user quota; clients behind a proxy may share that address. The checked transport also manages session IDs, which identify protocol sessions rather than proving ownership of every scene a tool can access.
Protect data mutations and imported content separately
For overwriting an existing named scene, save requires expectedVersion and checks it in a transaction. That helps prevent a stale writer from silently replacing current state, but it does not decide whether the caller should be allowed to write the scene. Keep local service credentials private and design explicit resource authorization before adapting the service to shared hosting.
Treat imported scene files, plugins and asset URLs as untrusted inputs. Validate structure, inspect warnings, constrain asset origins and retain recoverable project exports. Graph repair is not a sanitizer for every plugin or a professional safety assessment of a building. We inspected source and isolated helpers, not a running authenticated service or a full security test.
Implementation steps
- 1
Keep the local service on loopback and protect token files.
- 2
Review accepted origins and any reverse-proxy address sharing.
- 3
Require observed versions for overwrites and handle conflicts.
- 4
Review imports, plugins and assets before granting write access.
Copy-ready example
{"loopbackOnly":true,"sharedTokenIsTenantAuthorization":false,"overwriteNeedsExpectedVersion":true,"importsRequireReview":true,"publicMcpExposure":false,"securityIntegrationExecuted":false}Frequently asked questions
Is the rate cap 120 tool calls per user?
No. The inspected default counts /mcp HTTP requests per remote socket address, not tool calls or authenticated users.
Does expectedVersion authorize a write?
No. It checks concurrency. Resource authorization is a separate responsibility of the hosting integration.
Sources
- README.mdSource checked 2026-09-08
- LICENSESource checked 2026-09-08
- packages/cli/package.jsonSource checked 2026-09-08
- packages/core/package.jsonSource checked 2026-09-08
- packages/viewer/README.mdSource checked 2026-09-08
- packages/cli/src/runtime.tsSource checked 2026-09-08
- packages/cli/src/editor-process.tsSource checked 2026-09-08
- packages/cli/src/mcp-connector.tsSource checked 2026-09-08
- packages/mcp/src/transports/http.tsSource checked 2026-09-08
- packages/mcp/src/storage/sqlite-scene-store.tsSource checked 2026-09-08
- packages/core/src/store/use-scene.tsSource checked 2026-09-08
- packages/viewer/src/components/renderers/node-renderer.tsxSource checked 2026-09-08
- packages/viewer/src/lib/renderer-capability.tsSource checked 2026-09-08
- packages/core/src/validation/validate-build-json.tsSource checked 2026-09-08
- packages/core/src/utils/heal-scene-graph.tsSource checked 2026-09-08
- packages/mcp/src/storage/slug.tsSource checked 2026-09-08