Guard against DEV_DISABLE_OAUTH being enabled in production/staging#369
Open
sebastiondev wants to merge 2 commits into
Open
Guard against DEV_DISABLE_OAUTH being enabled in production/staging#369sebastiondev wants to merge 2 commits into
sebastiondev wants to merge 2 commits into
Conversation
…environments Add a runtime assertion that throws if DEV_DISABLE_OAUTH is set to "true" while ENVIRONMENT is "production" or "staging". This prevents accidental misconfiguration from bypassing OAuth and granting unauthenticated access via the dev API token. The guard is added to both isApiTokenRequest() and handleApiTokenMode() as defense-in-depth, since either function could be called independently. CWE-200: Information Exposure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a runtime guard preventing
DEV_DISABLE_OAUTHfrom being active in production or staging environments. Today, if bothDEV_DISABLE_OAUTH=trueandDEV_CLOUDFLARE_API_TOKENare set on a deployed Worker, OAuth is bypassed for every incoming request and any caller is authenticated as the operator-supplied dev token. The change is small (~14 lines) and localized topackages/mcp-common/src/api-token-mode.ts.I want to be upfront that this is a defense-in-depth / misconfiguration hardening fix, not a directly attacker-triggerable vulnerability — the precondition is operator error. But the blast radius if it ever happens is total auth bypass, so failing fast at startup felt like the right tradeoff.
The issue
In
packages/mcp-common/src/api-token-mode.ts:When this branch is taken,
isApiTokenRequestreturnstrueunconditionally andhandleApiTokenModethen authenticates the request usingDEV_CLOUDFLARE_API_TOKEN/DEV_CLOUDFLARE_EMAIL. There is no check that the deployment is actually a dev environment. If those env vars ever get copied into a production Worker secrets file (or a staging secrets file gets promoted without auditing), every public request to the MCP server is implicitly trusted.The wrangler configs for
apps/workers-observability,apps/logpush, andapps/dex-analysisall setENVIRONMENTper-environment (development/staging/production), so a guard keyed onENVIRONMENTis reliable across the affected apps.This maps most cleanly to CWE-489 (Active Debug Code) / CWE-1188 (Insecure Default Initialization of Resource) — a dev-only auth shortcut with no environmental gate.
The fix
Add
assertDevOAuthNotInProd(env)at both entry points to the dev shortcut (isApiTokenRequestandhandleApiTokenMode). It throws ifDEV_DISABLE_OAUTH === 'true'andENVIRONMENTisproductionorstaging:Rationale:
development(or unsetENVIRONMENT), so local workflows are unaffected.env.DEV_DISABLE_OAUTHchecks elsewhere incloudflare-api.tsare post-auth and don't matter once this gate refuses to open.Tests
Added
packages/mcp-common/src/api-token-mode.spec.tscovering:DEV_DISABLE_OAUTH=true+ENVIRONMENT=productionDEV_DISABLE_OAUTH=true+ENVIRONMENT=stagingDEV_DISABLE_OAUTH=truewhenENVIRONMENT=developmentDEV_DISABLE_OAUTH=truewhenENVIRONMENTis unsetisApiTokenRequestandhandleApiTokenModeenforce the guardFull suite passes locally (99/99).
Adversarial review
Before submitting I tried to talk myself out of this. The honest version: an attacker can't trigger this on their own — it requires an operator to set
DEV_DISABLE_OAUTH=trueandDEV_CLOUDFLARE_API_TOKENon a prod/staging Worker. So is it worth a guard? I think yes, because (a) those env vars are a plausible copy-paste mistake when promoting configs, (b) there is currently no signal at all when the bypass is active in prod — the server just works, with no auth, and (c) the failure mode is unauthenticated access to all configured Cloudflare API operations under the operator's token. A startup-time hard error is a cheap way to make the misconfiguration impossible to ship silently. Happy to drop or rescope this if you'd prefer a warning log instead of a throw, or a different env-var name convention.cc @lewiswigmore