The Problem With "Just Don't Put Keys Here"
Documentation comments are not security controls.
In the platforms/m365/wrangler.toml file for this Cloudflare Workers deployment, a comment instructed developers to set ANTHROPIC_API_KEY and API_TOKEN via wrangler secret put. That's correct advice. But the comment sat directly adjacent to the [vars] section — the exact place where a developer under deadline pressure might paste a key "just to test something" and accidentally commit it.
That's the vulnerability: not a missing encryption library, not a broken authentication flow, but a configuration file that was one distracted commit away from leaking production credentials into version control forever.
The Vulnerability Explained
What Makes [vars] Dangerous for Secrets
Cloudflare Workers has two ways to inject values into a Worker's environment:
[vars]inwrangler.toml— plaintext key-value pairs, committed to git alongside your codewrangler secret put— encrypted secrets stored in Cloudflare's secret store, never written to disk or version control
The distinction is critical. Anything in [vars] is:
- Committed to git in plaintext
- Visible in every clone, fork, and CI/CD log that checks out the repo
- Permanent in git history, even if later deleted
Here's what the vulnerable section looked like before the fix:
# platforms/m365/wrangler.toml (before fix, line 7-11)
ALLOWED_ORIGINS = ""
# Set secrets via:
# wrangler secret put ANTHROPIC_API_KEY
# wrangler secret put API_TOKEN
The problem isn't what's written — it's what's missing. There's no barrier between the [vars] block above and the comment below. A developer who sees ALLOWED_ORIGINS = "" and needs to add ANTHROPIC_API_KEY for local testing might naturally write:
# DANGEROUS — do not do this
[vars]
ALLOWED_ORIGINS = ""
ANTHROPIC_API_KEY = "sk-ant-api03-..." # ← now in git forever
API_TOKEN = "Bearer eyJ..." # ← same
Once that commit is pushed — even to a private repository — the key is in the git object database. Deleting the line in a follow-up commit does not remove it from history.
The Attack Scenario
The PR's exploitation scenario is concrete: an attacker gains read access to the repository via leaked Git credentials, an exposed CI/CD log, or a compromised developer account. With that access, they run:
git log --all --full-history -- platforms/m365/wrangler.toml
git show <commit-hash>:platforms/m365/wrangler.toml
If an ANTHROPIC_API_KEY was ever committed to [vars], it appears in plain text. The attacker now has:
- Full access to the Anthropic API under the victim's billing account
- Potentially unbounded LLM API spend
- Access to any conversation history or fine-tuning data tied to that key
The API_TOKEN exposure is similarly severe — depending on what it authenticates, it could grant access to M365 data, admin endpoints, or downstream services.
Why the 503 Fallback Doesn't Help
The codebase includes a defensive control: when secrets are missing at runtime, the Worker returns a 503 error rather than proceeding without credentials. This is good practice — but it protects against absent secrets, not exposed ones. If a key is committed to git, it isn't missing. The Worker runs fine. The attacker also runs fine, using the same key from outside the Worker entirely.
The Fix
The fix is two targeted changes that together close the gap between documentation intent and developer behavior.
Change 1: Explicit Warning in wrangler.toml
# Before
# Set secrets via:
# wrangler secret put ANTHROPIC_API_KEY
# wrangler secret put API_TOKEN
# After
# WARNING: NEVER add ANTHROPIC_API_KEY or API_TOKEN to [vars] above.
# [vars] is committed to git and is NOT encrypted. Use wrangler secrets:
# wrangler secret put ANTHROPIC_API_KEY
# wrangler secret put API_TOKEN
The change is minimal in lines but significant in intent. The original comment read like a suggestion. The new comment reads like a guardrail. By naming the specific variables (ANTHROPIC_API_KEY, API_TOKEN) and explaining why [vars] is unsafe ("committed to git and is NOT encrypted"), the warning gives a developer the information they need at the exact moment they might make the mistake.
This is the principle of contextual security guidance — security instructions are most effective when they appear at the point of decision, not in a README three directories away.
Change 2: .dev.vars Added to .gitignore
# .gitignore
+# Cloudflare Workers local dev secrets — must never be committed
+.dev.vars
+
# Internal lead documents — not for public consumption
Cloudflare Workers supports a .dev.vars file for local development — it's the local equivalent of wrangler secret put, letting developers set secret values for wrangler dev without touching wrangler.toml. But .dev.vars is only safe if it's gitignored. Without this entry, a developer creating .dev.vars for local testing could accidentally commit it.
The comment in the .gitignore entry matters too: "must never be committed" explains the why, making it less likely a future developer will remove the entry thinking it's unnecessary.
What This Fix Does NOT Do (And Why That's Okay)
This fix doesn't add runtime enforcement — it doesn't fail the build if [vars] contains a secret-shaped value. That would be a stronger control, but it's also a more invasive change. The current fix correctly scopes the change to the minimum necessary: clear guidance at the point of risk, and a gitignore entry that closes the .dev.vars vector. The PR notes that "the project's existing tests still pass, so intended behavior is unchanged."
Prevention & Best Practices
1. Use Wrangler Secrets for All Sensitive Values
# Correct approach for all secrets
wrangler secret put ANTHROPIC_API_KEY
wrangler secret put API_TOKEN
# For local dev, use .dev.vars (gitignored)
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> .dev.vars
Never use [vars] for anything you wouldn't want in a public git repository.
2. Audit Git History for Committed Secrets
If you suspect a secret was ever committed, don't just delete it — rotate it immediately and scan history:
# Scan git history for secret patterns
trufflehog git file://. --since-commit HEAD~100
git-secrets --scan-history
Tools like truffleHog, gitleaks, and git-secrets can find secrets in historical commits.
3. Pre-commit Hooks
Add a pre-commit hook that blocks commits containing secret patterns:
# Install gitleaks as a pre-commit hook
gitleaks protect --staged
Or use the pre-commit framework with the detect-secrets hook.
4. CI/CD Secret Scanning
Enable GitHub's built-in secret scanning (Settings → Security → Secret scanning) and push protection. This blocks pushes containing known secret formats before they reach the remote.
5. Principle of Least Privilege for Config Files
Review every configuration file in your repository and ask: "If this file were public, what would be exposed?" Config files that need secrets should reference environment variables or secret store paths — never inline values.
OWASP and CWE Alignment
This vulnerability maps to:
- CWE-312: Cleartext Storage of Sensitive Information
- CWE-798: Use of Hard-coded Credentials
- OWASP A02:2021 — Cryptographic Failures (storing sensitive data without encryption)
- OWASP A05:2021 — Security Misconfiguration (insecure default configuration patterns)
Key Takeaways
wrangler.toml[vars]is git-committed plaintext — treat it like a public file and never storeANTHROPIC_API_KEY,API_TOKEN, or any credential there, regardless of how temporary the intent is.- A comment saying "don't do X" is not a control — the original comment correctly pointed to
wrangler secret put, but without a warning explaining why, it provided no friction against the dangerous alternative. .dev.varsneeds to be gitignored explicitly — Cloudflare's local dev secrets file is only safe if it never reaches version control; the absence of this gitignore entry was a second vector for the same class of exposure.- Git history is permanent — rotating a key after committing it is mandatory, not optional. Deleting the line in a follow-up commit does not remove it from
git log. - Contextual warnings outperform distant documentation — the fix's
WARNING: NEVER add ANTHROPIC_API_KEY or API_TOKEN to [vars]comment is more effective than any README section because it appears at the exact point of risk.
How Orbis AppSec Detected This
- Source: The
[vars]section ofplatforms/m365/wrangler.tomlat line 11, where environment variables are defined in plaintext and committed to version control - Sink: Any git clone, CI/CD checkout, or repository browser that reads
wrangler.toml— the "dangerous call site" is the git commit itself, which permanently stores the value - Missing control: No explicit prohibition against placing
ANTHROPIC_API_KEYorAPI_TOKENin[vars]; no.dev.varsgitignore entry to block the local dev secret file from being committed - CWE: CWE-312 — Cleartext Storage of Sensitive Information
- Fix: Added a
WARNINGcomment naming the specific forbidden variables and explaining that[vars]is git-committed plaintext, plus added.dev.varsto.gitignore
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
The vulnerability in platforms/m365/wrangler.toml is a reminder that security misconfiguration doesn't require a sophisticated exploit — sometimes it just requires a developer who doesn't know which config section is safe for secrets. The fix is small: two files, a warning comment, and a gitignore entry. But the impact is significant: it closes the gap between "we told developers to use wrangler secrets" and "we made it hard for developers to accidentally do the wrong thing."
Cloudflare Workers makes secret management easy with wrangler secret put. The failure mode here wasn't a missing feature — it was a missing guardrail. The lesson for any project using configuration files: document the safe path, warn against the unsafe path, and use tooling to enforce the difference.