CMS OAuth Worker Safety Gate — 2026-05-29

CMS OAuth Worker Safety Gate — 2026-05-29

CMS OAuth Worker Safety Gate — 2026-05-29

이 artifact는 /admin/ CMS와 Cloudflare Worker OAuth broker를 Pages 배포와 분리해 추적한다. Pages 사이트는 live route proof를 통과했지만, Worker hardening은 아직 live-proven 상태가 아니다.

Verified Originals

sourceclassoperating grammar extracted
RFC 9700: OAuth 2.0 Security Best Current PracticeIETF BCPOAuth browser flow에서는 authorization response/token leakage와 redirect/origin 경계를 별도 공격면으로 다뤄야 한다.
GitHub OAuth scopesofficial platform documentationpublic_repo는 public repository access에 제한되고, repo는 public/private repository access를 포함한다.
Decap CMS Backends Overviewofficial product documentationGitHub backend의 base_urlauth_endpoint가 CMS authentication request의 실제 OAuth broker를 결정한다.
MDN Window.postMessageprimary web platform documentation민감한 메시지는 wildcard target origin이 아니라 정확한 target origin으로 보내야 한다.
MDN CORS Guideprimary web platform documentationcross-origin access는 wildcard와 credential/token surface를 분리해 명시적 origin으로 제어해야 한다.

Current Evidence

surfacelocal source statelive proof state
CMS entrypointstatic/admin/index.html no longer loads Decap CMS while Worker proof is missing.Needs publication to prove /admin/ is locked live.
CMS configstatic/admin/config.yml is intentionally non-operational; the old working config is preserved only in docs/cms/decap-config.reference.yml.Needs publication to prove cached Decap shells cannot fetch an active default config.
Worker sourceworker/src/index.js requests public_repo, restricts CORS to configured origins, and uses exact CMS_ORIGIN for postMessage. This is a public-repo-model scope check, not private source repo write proof.Previous live smoke showed stale behavior: repo,user, wildcard CORS, wildcard postMessage.
Worker deploynpm --prefix worker run check passes dry-run bundle verification.npm --prefix worker run deploy fails without CLOUDFLARE_API_TOKEN.
Worker live checkscripts/check-worker-oauth.ps1 now codifies the required live smoke checks.Expected to fail until the hardened Worker is actually deployed.
CMS operating modelCMS OAuth Operating Model Gate records the private source repo vs public_repo restore blocker.Expected to fail restore readiness until a public target repo, private-repo-capable repo scope, or GitHub App model is selected and proven.

Safety Decision

Until Worker deployment succeeds and the CMS operating model gate is resolved, do not treat CMS OAuth as production-verified. Pages publication and /admin/config.yml freshness are proven separately from Worker OAuth safety. The current safety posture is to keep /admin/ disabled rather than warning-gated.

The next non-negotiable gate is:

$env:CLOUDFLARE_API_TOKEN = "<token with Workers Scripts edit access>"
npm --prefix worker run deploy
powershell -ExecutionPolicy Bypass -File scripts/check-worker-oauth.ps1

This gate proves only the live Worker safety posture for the public-repo-model OAuth request. Only after the Worker gate and the private-source operating model decision both pass should the CMS be treated as safe for normal login/edit/media workflows.

Claim Boundary

allowed claimforbidden claim
The source Worker is hardened and dry-run verified.The live Worker is hardened.
The source site disables the default CMS entrypoint and default config until Worker proof exists.The live CMS OAuth flow is safe to rely on.
The live Worker check is now scripted.A scripted check is equivalent to a successful Worker deploy.
public_repo is a public-repo-model scope target.public_repo proves writable CMS access to the current private source repo.

Next Proof

After deployment, add a follow-up proof artifact with:

  • npm --prefix worker run deploy success output.
  • scripts/check-worker-oauth.ps1 success output.
  • The selected operating model from CMS OAuth Operating Model Gate.
  • A live Decap login/edit/media upload proof.
  • An unauthorized-account denial proof.
  • A token revocation note for any old broad-scope GitHub OAuth grants.
  • A commit that restores static/admin/index.html to load Decap and restores the reference config as static/admin/config.yml.