Skip to Content
Security and SharingSet safe Energon boundaries

Configure a production Energon so authenticated hub activity stays separate from published active content, token ownership stays inside the intended personal or organization boundary, mutations default to the creator, and content expires. These boundaries matter because a healthy Worker can still expose content or authority through a bad policy. This guide gives operators a conservative baseline plus checks for each boundary.

Set safe Energon boundaries

1. Give the hub and content different origins

Set two custom hostnames. The hub origin (PUBLIC_ORIGIN) serves the human hub and /v1 API. The content origin (CONTENT_ORIGIN) serves published sites and files.

wrangler.toml
[vars] PUBLIC_ORIGIN = "https://energon.company.example" CONTENT_ORIGIN = "https://content.energon.company.example" TOKEN_ENV = "COMPANY_ENERGON_TOKEN" TOKEN_PREFIX = "ee_live_"

Attach both hostnames to the Worker. In production, Energon rejects a missing, malformed, or same-as-hub content origin when it needs to publish or serve content. The same origin is permitted only for localhost development.

People browse the hub with an Access session, while teams may publish HTML, SVG, XML, or Markdown supplied by an agent. A dedicated content hostname prevents that active content from sharing the hub’s authenticated origin. Energon also adds a sandbox CSP to active documents (HTML, XHTML, SVG, and XML types), with origin separation as the outer boundary.

Do not put Cloudflare Access on the content hostname. Recipients are meant to open content links without an operator session, and the Worker does not serve hub account routes there. Put confidential material behind an object share password, or use a system with reader-specific authorization when a shared password is insufficient. A write password lets an outsider replace bytes at that URL; it is not Access and is not a token.

2. Configure Cloudflare Access by path

On the hub hostname, configure Access to allow only the intended individual or organization members on:

/ /account* /about /stats /admin /setup /tokens /connect

Bypass Access for the routes that use their own protocol:

/v1* /health /llms.txt /auth.md /favicon.svg /static*

Agents do not carry an Access cookie; /v1 authenticates file operations with Authorization: Bearer. Discovery and connection requests remain public, but agent keys are delivered only after human approval. Public content paths on CONTENT_ORIGIN also bypass Access. That includes the well-known skill under /.well-known/agent-skills/, added in v1.12.0. It is served only on the content hostname, so the hub list above needs no new entry, and it publishes the same origins, token environment name, and token prefix that /v1/help already reports, with no credentials. Set AGENT_SKILLS_DISCOVERY = "false" if you do not want it served.

Energon application code rejects human hub requests on *.workers.dev, but disable or ignore that hostname for humans as well. Keep the custom hub hostname as the only place where people establish an Access session.

3. Add a second identity boundary

For an organization Energon, restrict the Access identity provider to the organization, then set the same email-domain intent in Energon:

wrangler.toml
[vars] ALLOWED_EMAIL_DOMAINS = "company.example"

The Worker applies this allowlist to both verified Access identities and the owners of agent keys. This catches a mis-aimed Access policy before an outside email can create an agent key or create a user row. An empty allowlist accepts any email that Access verifies.

For a personal Energon, restrict Access to the operator’s exact identity. If that identity uses a shared consumer domain, leave ALLOWED_EMAIL_DOMAINS empty rather than allowing the entire domain, and treat the narrow Access rule as the identity boundary.

Use the stable IdP subject supplied by Cloudflare Access. Energon binds owner-only content to that subject-backed user id. If an email is reassigned to a new subject, the old account’s tokens are revoked and its owner-only objects do not transfer.

4. Choose the mutation boundary explicitly

For a conservative default, make new objects creator-only:

wrangler.toml
[vars] WRITE_POLICY = "owner"

Use org only when every valid agent key on this host should be able to overwrite and delete newly created work. The setting is copied at creation; it does not retroactively change existing sites or files. A creator can override the default on create and later PATCH the stored policy.

export ENERGON_ORIGIN="https://energon.company.example" test -n "$COMPANY_ENERGON_TOKEN" || { echo "Set the human-authorized token" >&2; exit 1; } curl -sS "$ENERGON_ORIGIN/v1/sites" \ -H "Authorization: Bearer $COMPANY_ENERGON_TOKEN" \ -H "Content-Type: application/json" \ --data '{"slug":"release-notes","write_policy":"owner","ttl":"7d"}'

Remember that this controls mutation only. Every valid agent key on this Energon can still read a public object through /v1 and duplicate it into a new object. Only private link access limits reads to the creating account.

5. Set content and token clocks separately

This explicit baseline requires content to expire within 30 days and removes never from future token-mint choices:

wrangler.toml
[vars] ALLOW_UNLIMITED_RETENTION = "false" DEFAULT_TTL = "7d" MAX_TTL = "30d" ALLOW_UNLIMITED_TOKENS = "false"

Content and token settings do not affect one another:

ALLOW_UNLIMITED_TOKENS = "false" affects future mints only. Audit and revoke existing tokens whose expires_at is null if your policy no longer permits them. Do not roll the Worker back below the first version that enforces token expiry while finite, unrevoked tokens exist; an older build would ignore their expiry.

The scheduled expiry sweep should remain configured. Reads still return 410 immediately after content expiry, even if a cron run fails, but the sweep removes expired R2 bytes and catalog rows.

6. Verify from both sides of the boundary

First, confirm that public metadata is reachable without a credential and advertises the expected identity and policies:

export ENERGON_ORIGIN="https://energon.company.example" curl -sS "$ENERGON_ORIGIN/v1/health" curl -sS "$ENERGON_ORIGIN/v1/help" | jq '{hub, content_origin, env, token_prefix, retention, tokens}'

Then verify a human-authorized token without printing it:

test -n "$COMPANY_ENERGON_TOKEN" || { echo "Set COMPANY_ENERGON_TOKEN" >&2; exit 1; } curl -sS "$ENERGON_ORIGIN/v1/whoami" \ -H "Authorization: Bearer $COMPANY_ENERGON_TOKEN"

Finally, check the host split in a browser or with headers:

curl -sS -D - -o /dev/null "https://energon.company.example/example/s/security-check/" curl -sS -D - -o /dev/null "https://content.energon.company.example/account"

The first request should redirect to the content origin when the object path is valid. The content hostname must not serve the account route. A real published HTML, SVG, or XML response should include a sandbox Content-Security-Policy; a password-protected response should use private, no-store caching.

A successful health check proves only that the Worker is running. It does not prove Access paths, email domains, write policy, content-host routing, or cache behavior. Verify each boundary after deployment and whenever routing or policy variables change.

7. Handle credentials and reports safely

Before approving a connection, match the displayed host to the agent’s requested host, confirm the signed-in account and label, and read the access disclosure. Approval issues an account token, including Energon-wide API read access. An unattended run with no credential must stop for human provisioning instead of opening a connection nobody can approve.

Save a delivered token before use. Prefer the environment’s credential store. Otherwise persist it in a user-level environment file, shell profile, or home-directory file outside the project, readable only by the current user (mode 600 on Unix, in a private directory). Report its location, label, and expiration without the secret. If storage is ephemeral, explain that the next session needs another approval or a provisioned credential. See Connect an agent for the complete flow.

  • Never invent, commit, or paste a live Energon token into documentation or an issue.
  • Revoke a leaked token from /keys; it cannot be recovered or renewed. Revoking it also ends every upload grant it minted.
  • Avoid logging the token-mint response because it contains the one-time secret.
  • Treat share passwords, write passwords, and customer file contents as sensitive report material.
  • Report code vulnerabilities through GitHub private vulnerability reporting, including the tested commit, reproduction steps, and attacker impact.
  • Fix an deployment-only misconfiguration, such as an open Access policy or exposed hub hostname, on that Energon without publishing its credentials.

Continue reading

Last updated on