The first security question every agent user hits is also the one most users answer wrong: where do I put my API keys? The default answer is wrong. Most people paste the key into the Discord channel where the agent is listening, or commit a .env file to the Git repo, or hardcode it in a config script. Every one of those is a leak. The discipline this article teaches is simple: secrets live in ~/.openclaw/.env with chmod 600 permissions, the model is trained not to reveal them, and the file is in .gitignore from day one. The v2.26 release (cross-referenced in 9.2) adds a platform-native version of the same rule.
This article walks through the discipline, the verification, the platform-specific patterns (Notion, Discord, Telegram), the Git hygiene, and the incident-response flow when something does leak.
What you'll learn
- The "Golden Rule" of the channel's security primer: never share API keys, tokens, or secrets in chat platforms (Discord, WhatsApp, Slack, Telegram), because even "I'll delete it later" leaks via caches, notification previews, screenshots, bot logs, and team-member access.
- The right location is
~/.openclaw/.envwithchmod 600permissions — the model is trained not to reveal env vars, the OS protects the file at the user level, and the file is easy to.gitignoreand easy to rotate. - The format is one
KEY=valueper line:NOTION_API_KEY=secret_abc...,DISCORD_BOT_TOKEN=...,TELEGRAM_BOT_TOKEN=1234567890:ABC..., plus your model API key (OPENAI_API_KEY,ANTHROPIC_API_KEY) and any third-party service (YOUTUBE_TRANSCRIPT_API_KEY,COINGECKO_API_KEY,TWITTER_API_KEY). - The platform-specific rotation flows: Notion "Regenerate" → update
.env→openclaw gateway restart; Discord "Reset Token" in Developer Portal → update → restart; Telegram/revokethen/tokenvia BotFather → update → restart. - The
.gitignoreblock that protects you:.env,.env.local,.env.*.local,**/.env, plus the OpenClaw-specific.openclaw/.envand.openclaw/**/.env. - The incident response for a leaked key: revoke at source within 5 minutes, generate a new one, update
.env, restart the gateway, audit logs within 24 hours, document the incident.
The Golden Rule: never share keys in chat
The first video in the syllabus (cross-listed with 9.2 and 9.3) is the channel's "your agent is acting stupid" primer. The .env discipline is item 1 of 4 in the "how to fix it" flow. The Golden Rule is unambiguous: never share API keys, tokens, or secrets in chat platforms like Discord, WhatsApp, Slack, or Telegram.
The reasoning is the part most users skip. Even if you plan to delete the message, the secret has already propagated to:
- Platform caches — Discord, Slack, and Telegram all cache messages server-side, and the cache lifetime is rarely the same as your "delete" intent.
- Notification previews — mobile notification previews show truncated message bodies, and screenshot automation routinely scrapes them.
- Screenshots — every participant in the channel can screenshot before the delete propagates. The threat model is not "I trust my team," it is "I trust my team's screenshots."
- Bot or integration logs — every other bot with read access to the channel has now seen the key. Some of those bots are third-party services you don't own.
- Other team members — the channel is the wrong granularity. Pair-based sharing beats channel-based sharing for any secret.
The public.videos.summary_content for the video frames the four fixes as: (1) break down complex tasks, (2) provide API documentation first, (3) mandate testing at each step, (4) limit permissions. The .env discipline is part of (4) — limit the agent's blast radius by keeping secrets out of the surface area the agent can read or write.
Wrong vs right
# Wrong
Discord: "Hey team, here's the Notion API key: secret_abc123..."
# Right
Discord: "I've added the Notion integration. Each team member
should create their own integration at notion.so/my-integrations
and add it to their local .env file."
The "right" version puts the secret in ~/.openclaw/.env on each team member's machine, where the OS protects it at the user level and the model is trained not to reveal it.
Environment variables: why they work
The "why" matters because the discipline is a tax, and people skip taxes they don't understand. Five reasons env vars are the right home for secrets:
- AI models are trained not to reveal them. OpenClaw's model layer is trained to treat env-var contents as protected. The key never enters chat output unless you explicitly ask for it, and even then, the trained response is a refusal or a redaction.
- File permissions protect at the OS level.
chmod 600on the file means only your user can read or write it. Other users on a shared box — including the agent's runtime user, if you isolate it correctly — cannot read the file. - Secrets stay separate from code and chat logs. The same secret can be referenced by ten different skills, five different integrations, and three different cron jobs, without ever appearing in a config file the agent edits.
- Version control is trivial to exclude. One
.gitignoreline protects you forever. The reverse — auditing a repo for leaked secrets — is hard. - Easy rotation. Edit the file, restart the gateway, done. No code changes, no config-tree edits, no skill rewrites.
Setting up the file
The location is ~/.openclaw/.env, the permissions are chmod 600, and the editor is nano (because it's installed everywhere and doesn't try to do smart things with trailing whitespace).
# Create the directory if it doesn't exist
mkdir -p ~/.openclaw
# Create the .env file with restricted permissions
touch ~/.openclaw/.env
chmod 600 ~/.openclaw/.env
Edit with nano:
nano ~/.openclaw/.env
In nano: Ctrl + X to exit, Y to confirm save, Enter to confirm filename.
The format
One secret per line, in KEY=value format, with a comment per integration. The channel's recommended block:
# Notion Integration
NOTION_API_KEY=secret_abc123XYZ456def789
# Discord Bot
DISCORD_BOT_TOKEN=MTIzNDU2Nzg5MDEyMzQ1Njc4OQ.GhIjKl.MnOpQrStUvWxYzAbCdEfGhIjKlMnOpQrStUv
# Telegram Bot
TELEGRAM_BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz1234567890
# YouTube Transcripts API
YOUTUBE_TRANSCRIPT_API_KEY=yt_live_abc123def456ghi789
# Custom APIs
COINGECKO_API_KEY=CG-abc123def456ghi789jkl012
TWITTER_API_KEY=AAAAAAAAAAAAAAAAAAAAABcde
Model API keys live in the same file:
# Model provider
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
Verification
After creating the file, check the permissions:
ls -la ~/.openclaw/.env
The expected output:
-rw------- 1 username username 256 May 6 12:00 /home/username/.openclaw/.env
The -rw------- means only your user can read/write the file. If you see -rw-r--r-- (world-readable) or -rw-rw-r-- (group-readable), the file is unsafe — re-run chmod 600.
Platform-specific flows
Each platform has a different key-management UI, but the .env discipline is the same. The channel documents three of the most common.
Notion
- Where to get the key: notion.so/my-integrations → create integration → copy "Internal Integration Secret."
- Environment variable:
NOTION_API_KEY=secret_your_key_here. - Permissions: use read-only if you only need data analysis; enable write for task management.
- Rotation: click "Regenerate" in integration settings → update
.env→openclaw gateway restart.
Discord
- Where to get the key: discord.com/developers/applications → create application → Bot → Reset Token.
- Environment variable:
DISCORD_BOT_TOKEN=your_token_here. - Security settings: enable "Server Members Intent" and "Message Content Intent" before you save the bot page (the two intents have to be on before the token is generated, otherwise the bot will be online but unable to read messages). Use specific permissions, not Administrator, whenever possible.
- Rotation: Reset Token in Developer Portal → update
.env→ restart gateway → bot reconnects automatically.
Telegram
- Where to get the key: message @BotFather on Telegram →
/newbotcommand → copy the token. - Environment variable:
TELEGRAM_BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz. - Security settings: configure pairing policy (DM only, allowlist, etc.) → use pairing codes for new users → review paired users monthly.
- Rotation: message @BotFather →
/revoke→/token→ update.env→ restart gateway.
Third-party APIs
The pattern is SERVICE_NAME_API_KEY=your_key_here. Common examples from the channel's coverage:
YOUTUBE_TRANSCRIPT_API_KEY— YouTube Transcripts APICOINGECKO_API_KEY— CoinGecko crypto dataOPENAI_API_KEY— OpenAIANTHROPIC_API_KEY— Anthropic Claude
Git and version control
The .gitignore block that protects you on day one:
# Environment variables
.env
.env.local
.env.*.local
**/.env
# OpenClaw specific
.openclaw/.env
.openclaw/**/.env
The **/.env pattern catches env files in subdirectories, which matters if you have multi-agent setups or per-skill configurations. The .openclaw/**/.env pattern is OpenClaw-specific and protects any .env file the agent creates inside its own directory tree.
Before every commit
# Check what will be committed
git status
# Search for potential secrets in staged files
git diff --cached | grep -i "api_key\|token\|secret\|password"
The grep is a last-line defence. If it returns anything, the commit is unsafe. Use --cached to scan only staged files, not the whole working tree.
If you accidentally commit secrets
Three steps, in order:
- Immediately rotate all exposed keys. This is the most important step. The commit is already public the moment it lands, regardless of what you do with Git history.
- Remove from Git history (only if the secret has never been public — which you cannot reliably know):
# Remove file from Git history (use with caution)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch .env" \
--prune-empty --tag-name-filter cat -- --all
# Force push (only if you're sure)
git push origin --force --all
- Better approach: treat the repo as compromised and rotate all secrets. The
filter-branchrewrite is technically correct but practically leaky — every clone, every fork, every CI cache, every mirror has the secret. Rotation is the only durable fix.
Access control: principle of least privilege
The "principle of least privilege" — only grant the minimum permissions needed — is the same shape across every integration. The channel's reference table:
| Use Case | Notion Permissions | Discord Permissions | Telegram Policy |
|---|---|---|---|
| Data Analysis | Read only | N/A | Read only |
| Task Management | Read + Write | Send messages, Read history | DM pairing |
| Team Collaboration | Read + Write | Manage channels, Send messages | Allowlist |
| Public Bot | Read + Write | Limited to specific channels | Pairing codes |
Monthly audit checklist
- Review all active API integrations
- Remove unused integrations
- Check who has access to
.envfiles - Verify bot permissions haven't expanded
- Review paired Telegram users
- Check Discord bot role assignments
- Rotate keys for critical services
The discipline is a calendar event, not a memory event.
Incident response
Two scenarios, both with concrete time-bound steps.
If an API key is exposed
Immediate actions (within 5 minutes):
- Revoke the exposed key at the source (Notion, Discord, etc.)
- Generate a new key
- Update your
.envfile with the new key - Restart the OpenClaw gateway:
openclaw gateway restart
Follow-up actions (within 24 hours):
- Review logs for unauthorized access — look for API calls from IPs you don't recognise, calls at times you weren't active, and reads of resources you don't normally touch
- Check for unexpected changes in connected services
- Notify team members if it's a shared integration
- Document the incident and how it happened
- Update procedures to prevent recurrence
If the .env file is compromised
Immediate actions:
- Rotate ALL keys in the
.envfile - Check system logs for unauthorized access:
sudo grep "\.env" /var/log/auth.log - Review recent file access:
ls -lu ~/.openclaw/.env - Change system passwords if needed
Follow-up actions:
- Enable 2FA on all integrated services
- Review SSH access logs
- Consider changing SSH keys
- Audit all connected services for suspicious activity
The 24-hour window is the channel's default. Anything longer than that and the blast radius starts to include compliance exposure (GDPR, HIPAA, etc., depending on your jurisdiction and your data).
Try it yourself
The hands-on goal: a defensible .env setup, on disk, with verification you can run on demand.
- Create the file with the right permissions.
mkdir -p ~/.openclaw && touch ~/.openclaw/.env && chmod 600 ~/.openclaw/.env. Verify withls -la ~/.openclaw/.env— the permissions should be-rw-------. - Populate the file with your real keys. One per line, in
KEY=valueformat. Add a comment per integration. Do not paste keys into a chat app or a web form to "save them somewhere first" — that's the leak. - Add the
.gitignoreblock. All four lines:.env,.env.local,.env.*.local,**/.env, plus the OpenClaw-specific lines. Verify withgit check-ignore -v ~/.openclaw/.env— should print the matching pattern. - Run the pre-commit scan.
git diff --cached | grep -i "api_key\|token\|secret\|password". Should return nothing. - Set the rotation reminder. Calendar event 90 days out titled "Rotate agent secrets." Quarterly rotation is the channel's default.
- Test the incident response. Pick one integration (Notion is the easiest). Revoke the key at source. Generate a new one. Update
.env. Restart gateway. Verify the integration still works. The first time you do this under pressure is not the time to learn the flow. - Run the monthly audit checklist. Do it once now to baseline, then calendar it monthly. Most users find at least one unused integration or one expanded permission on the first run.
- Document your
.envschema. A short README in~/.openclaw/that lists which keys you expect to find, where to get them, and how to rotate them. The discipline scales only if the next person (or future-you) can recover from a clean box.
Common pitfalls
- Pasting keys into Discord "just to test" — the chat-platform surface is the wrong surface. Use the
nanoflow or the platform's secret-management UI. chmod 644on the.envfile — the default fortouchon some systems is world-readable. Re-runchmod 600explicitly. Verify withls -la.- Pasting a fresh top-level object into a non-empty config — this is the JSON-parse gotcha from Course 4: Claude Code & AI Coding §4.2. It applies to
settings.jsonand to any structured config the agent reads. Paste only the inner object and check the trailing comma. - Treating
chmod 600as a one-time setup — verify it after everycp, everymv, and everygit checkout. Permissions are not sticky across copies. - Skipping the
.gitignore— the default Git behaviour is to track every file in the working tree. The first commit is the leak; the.gitignoreis the prevention. - Rotating one key and assuming the rest are safe — the blast radius of a
.envleak is the whole file. If one key was in a screenshot, the other keys are compromised too. Rotate them all. - Trusting "I deleted the message" — Discord, Slack, and Telegram caches live longer than your delete intent. Notification previews have already fired. The team member has already screenshotted. The secret is out. Rotate.
- Hardcoding secrets in
config.py— the channel's anti-pattern #4. The fix isos.getenv("NOTION_API_KEY")and the sameKEY=valueenv-var format. - Using the same key across team members — every team member should have their own integration. The discipline is per-user, not per-team.
- Granting Administrator permission to a Discord bot "to make it work" — Administrator is a footgun, not a default. The channel's stance: use specific permissions, not Administrator. The fact that "Administrator" makes the bot work faster is a sign that the scope is wrong.
- Forgetting to restart the gateway after a rotation — the new key is in
.env, but the gateway is still using the old one in memory.openclaw gateway restartis the explicit handoff.
Sources
- My OpenClaw is STUPID (Here's how to Fix It) — 1,535 views ·
video_id: 9lcn8ZmqyJ0. The Golden Rule, the "your agent is acting stupid" symptom list, and the four-fixes framing. - NEW OpenClaw Update is HUGE! — 9,677 views ·
video_id: xGFzVdp3Ch0. v2.26 external secrets management (cross-listed in 9.2). Theaudit,configure,apply,reloadfour-command flow. - Supabase query —
SELECT video_id, title, views, summary_content, summary_key_takeaways FROM public.videos WHERE video_id = ANY(ARRAY['9lcn8ZmqyJ0', 'xGFzVdp3Ch0']);against projectttxdssgydwyurwwnjogq. - External references cited in the source:
- notion.so/my-integrations — Notion Internal Integration creation
- discord.com/developers/applications — Discord bot creation
- @BotFather on Telegram — Telegram bot creation and rotation
- OWASP API Security Top 10
- GitHub Secret Scanning