Copy safe project defaults and look up public, control, code-execution, storage, logging, and sharing boundaries.
localhost2137 assumes a trusted developer project on a developer machine or isolated CI worker. Start by excluding the default storage root:
.localhost2137/Use clearly fake local credentials. The checked config uses xoxb-local-crash-course and
local-crash-course-signing-secret; neither grants access to an external account. Use synthetic
records as well. Persistent worlds and failed test cleanup can retain their contents.
pnpm exec localhost doctor --json
pnpm exec localhost env --instance dev --format jsondoctor is read-only but can contain local paths and instance metadata. env intentionally prints
application-facing local credentials. Review both before sharing; neither output includes the
runtime control token.
| Surface | Intended caller | Protection | Authority |
|---|---|---|---|
/{instance}/{service}/* | Application or provider SDK | Authentication implemented by that plugin | Read or mutate one emulated service world |
/_/v1/*, except health | CLI, test harness, trusted automation | Daemon bearer token; browser-origin requests rejected | Create, reset, seed, inspect, advance, destroy, invoke operations |
/_/v1/health | Local discovery | Loopback binding only | Return runtime protocol health |
Files below storage.dir | Runtime and trusted local tools | Local account and filesystem permissions | Hold discovery metadata, local credentials, manifests, plugin state |
The health route is the only unauthenticated control route:
curl --silent http://127.0.0.1:2137/_/v1/health{ "data": { "status": "ok", "version": "v1" } }Loopback is a network boundary, not authorization between local processes. Another process running
as the same user may reach public routes and read project files. Do not treat 127.0.0.1 as tenant
isolation.
The runtime bearer token does not protect provider-shaped routes. They exist so an application can use its ordinary SDK or HTTP client. Each plugin owns its fake local credentials, request authentication, callback signatures, and provider-shaped rejection behavior.
A browser may call a public route when normal browser networking permits it. The control API's Origin rejection does not apply to application traffic. Do not put privileged setup operations on a public plugin route, and do not mistake a fake provider token for protection against hostile local code.
Never copy a production provider key into plugin config. A local emulator does not need external account authority. If a real key was used, revoke it at its source; resetting the local world cannot rotate it.
Except for health, a control request needs the current daemon bearer token. Any request carrying an
Origin header is rejected, the control API does not enable CORS, and JSON mutations require JSON
content type with a maximum body size of 64 KiB.
The daemon creates a new random token at startup and stores it as control-token below
storage.dir. The active descriptor, token, and generated .env use owner-only 0600 mode where
POSIX permissions are available. File mode is defense in depth; the storage root and local account
remain the trust boundary.
The CLI and test client read the token automatically. Direct authenticated HTTP is documented once in Plain HTTP control. Do not:
localhost run;If it leaks, stop and restart the daemon, remove the retained copy, and inspect affected instances. Rotation prevents later use; it does not undo completed mutations.
Loading config runs its imports. Plugins execute with the privileges of the runtime's Node process. There is no process, filesystem, or network sandbox between a plugin, another instance, and the host user.
Treat plugin installation like any development dependency that executes code: review its source and dependency/version policy, install it explicitly, keep config imports focused, and do not load an untrusted change merely to inspect metadata. Run untrusted code in a separate OS or CI boundary.
The plugin storage helper rejects absolute paths and traversal outside its service data directory. That prevents accidental helper misuse; it does not stop a plugin from calling Node filesystem or network APIs. Tracked fetch makes work observable, not firewalled. Instances isolate plugin-owned data and lifecycle, not code execution or permissions.
storage.dir may contain provider-shaped records, callback payload data, generated application
connection values, the control token, runtime discovery metadata, manifests, and plugin databases.
A custom root needs the same ignore treatment as .localhost2137/.
Structured-log attributes redact sensitive-looking keys and omit body-like values. This exact tested result shows the transformation:
{
"authorization": "[REDACTED]",
"circular": "[CIRCULAR]",
"nested": {
"payload": "[OMITTED]",
"token": "[REDACTED]",
"visible": "safe"
}
}Ordinary string values and the log message pass through unchanged. A plugin message or an attribute
such as note: "token is ..." can expose exactly what its author supplied. Logs are bounded
diagnostic evidence, not a privacy control or audit store.
Review localhost logs --json, localhost doctor --json, failure output, and retained storage paths
before posting them. Copy this source-synced section into a report and verify every item:
## Removed before sharing
- Runtime control token
- App-facing connection credentials and provider secrets
- Personal data and unrelated request bodies
- Unrelated environment variables and log entriesDestroy only explicitly owned worlds. Remove an explicitly owned temporary directory only after its runtime has closed. Never turn cleanup into a broad or wildcard path.
localhost env renders plugin connection values. localhost run overlays those values on the
child's inherited environment. Neither command injects the control token, and run does not
sanitize inherited variables. This reduces accidental exposure through localhost2137's connection
projection. It does not contain a same-user process: a Node process with the user's filesystem
privileges may read project files, including the stored control token, and call the control API.
A browser test needing privileged arrangement should perform it in the Node test harness or CLI, then pass only provider-shaped IDs or application-visible state into the browser. Origin rejection is an additional guard against browser-origin control traffic, not a sandbox or hostile-local-code boundary.
Run hostile application code under a separate OS/process account or in an isolated CI boundary appropriate to the threat model. Merely starting it as another process under the same user is not isolation.
Runtime boundaries identifies claims requiring another environment. Diagnose a failing scenario shows how to preserve useful evidence without deleting broad directories or publishing secrets.