{"slug": "my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust", "title": "My Self-Hosted AI Assistant Kept Overwriting Its Own API Keys: A Zero-Trust Postmortem", "summary": "A developer running a self-hosted AI assistant on a Hostinger VPS discovered that the agent was overwriting its own API keys on startup, causing persistent authentication errors. The developer implemented a zero-trust model, moving credentials outside the agent's writable surface and deploying a watchdog for file integrity monitoring. The incident highlights the need to treat AI agents as untrusted processes, applying security hardening principles even to self-built systems.", "body_md": "🦞\n\nCode for this post:sanitized watchdog + config-repair scripts at[github.com/backitupboys/ai-agent-zero-trust]\n\n*Part 1 of a series on running AI agents on real infrastructure without regretting it.*\n\nI've spent 20+ years administering infrastructure — Windows NT to Win2000 to well, you get it...PCAnywhere 😬... VMware, Nutanix, Azure, security hardening. I thought I understood untrusted actors on a network.\n\nThen I gave an AI agent write access to its own config files, and it taught me the lesson again from scratch.\n\nI run a self-hosted AI assistant — I call it \"The Doctor\" (Voyager and Tardis ref.) — in an OpenClaw container on a Hostinger VPS. It's a hobby project: part experiment, part obsession, part fun excuse to learn agentic architecture hands-on. The assistant talks to LLMs through an API gateway, authenticated with an API key stored in its config. I mean, if you're here, you prolly know already...\n\nStandard stuff.\n\nAfter granting magic access to \"do what it needs to be better.\"\n\nThe assistant started throwing persistent 401 authentication errors.\n\nI checked the config — the key was wrong. Fixed it. Working again.\n\nNext boot:\n\n401s. Had to ask Claude, what the heck was happening....!!! ???\n\nKey was wrong *again*\n\nHere's the part that took me longer to accept than it should have:\n\n**the assistant was overwriting its own API keys on startup.**\n\nIts initialization routine was \"helping\" by rewriting config files — including the credentials block — with stale or generated values. My own agent was hard coding expired api's. Every time it booted, it re-broke its authentication.\n\nI wasn't fighting an attacker. I was fighting a well-intentioned process with too much write access and no concept of oops.\n\n**Confirmed the failure mode** — diffed the config before and after boot to prove the agent was the writer; not me, not corruption, not the provider, using Claude.\n\n**asked Claude to fix it. Claude then Wrote Python patch scripts** to safely repair the config so I didn't have to hand-edit any a live files at 1 a.m. (`config_patch.py`\n\n)\n\n**Deployed a watchdog** — a cron job that validates the API key block on a schedule and restores the known-good value if the agent overwrites it Accidentally ;). (`keyguard_watchdog.sh`\n\n)\n\nThe watchdog worked. It was also a band-aid, and I knew while I was writing it, well, I felt it, basically: I was fighting a well-intentioned process with too much misguided (my fault) 🤦♂️write access.\n\nThe irony was, I was using agentic Ai to fix my agentic Ai 🙄. This no longer seemed like a constructive project. This was beginning to become a costly (75$ in a week) loop of over-complicating things.\n\n**An AI agent should be implemented exactly like any other untrusted process in a zero-trust model — no matter how helpful it is, and no matter that you built it.**\n\nEverything I'd apply to a third-party service applies to my own assistant:\n\nThe assistant never needed write access to its own credentials.\n\nAlthough I admit... I really wanted it to,\n\ncause freedom for me etc...\n\nKnown-good secrets now live outside the agent's writable surface, in a root-owned reference file Dashboard the agent cannot modify, that I had it create. I wanted an easier (for me) dashboard to give it the api's and other \"secrets\" The agent can read them; it just cannot make changes to it.\n\nConfigs the agent depends on but shouldn't manage is read-only to the agent. If a process doesn't need to write it, it can't write it. This is CIS-hardening thinking applied one layer up the stack.\n\nThe watchdog evolved from \"auto-repair the key\" to \"alert me when anything writes to files nothing should be writing to.\" File integrity monitoring for a hobby VPS sounds like overkill until your own agent is the insider threat :/.\n\nDuring the debugging session, keys got pasted into places keys get pasted when it's latenight zzz. They were rotated... um eventually.\n\nIf a credential has touched a chat window, a log, or a screenshot, it's burned — that rule doesn't relax because it's a personal project.(shhhh)🤫🤫\n\nEvery company is currently wiring AI agents into real infrastructure — ticketing systems, runbooks, CI pipelines, cloud consoles. The industry conversation is mostly about what agents *can* do. The operational conversation needs to be about what they *Can* mess up.\n\nMy assistant wasn't/isn't malicious (we hope). It wasn't compromised. It was doing exactly what its code said, with more authority than it needed (sadly) — which is the same root cause behind most insider incidents I've seen. The fact that the insider is a language model changes the tooling, not the principle:\n\nIf modern architectures assume no implicit trust for users and devices, AI agents should be governed tools within that system — not exempt operators.\n\nThat's the design principle I now start from, at home and at work.\n\n`git checkout`\n\n, not archaeology.None of that is exotic. It's the same discipline we apply to production servers — the only new part was admitting my helpful little assistant deserved the same suspicion as everything else on the wire.\n\n```\nai-agent-zero-trust/\n├── README.md                # this postmortem\n├── .gitignore               # keeps secrets out of the repo\n├── keyguard_watchdog.sh     # cron watchdog: detect + restore + alert\n└── config_patch.py          # safe, atomic config repair\n```\n\nBoth scripts are **sanitized reference implementations** of the approach described above — generic paths, placeholder variable names, no real credentials, no real hostnames. Adapt to your own stack; read every line before running anything from the internet as root, including this. (Especially this. That's the whole point of the article.)\n\n```\n# 1. Store the known-good key OUTSIDE the agent's writable surface (root-owned, 600)\necho \"sk-your-real-key\" | sudo tee /etc/keyguard/reference.key\nsudo chmod 600 /etc/keyguard/reference.key\n\n# 2. Test the watchdog manually\nsudo ./keyguard_watchdog.sh\n\n# 3. Schedule it (every 5 minutes)\n# crontab -e (as root):\n*/5 * * * * /opt/ai-agent-zero-trust/keyguard_watchdog.sh >> /var/log/keyguard.log 2>&1\n```\n\n*I'm a San Antonio-based systems administrator working at the intersection of infrastructure, security, and AI operations. Next up: how I turned 668 screenshots of after-hours incident response into an automated evidence pipeline with PowerShell and Python.*", "url": "https://wpnews.pro/news/my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust", "canonical_source": "https://dev.to/veranice/my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust-postmortem-4eec", "published_at": "2026-07-11 10:19:27+00:00", "updated_at": "2026-07-11 10:44:00.834723+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-infrastructure", "developer-tools"], "entities": ["Hostinger", "Claude", "OpenClaw", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust", "markdown": "https://wpnews.pro/news/my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust.md", "text": "https://wpnews.pro/news/my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust.txt", "jsonld": "https://wpnews.pro/news/my-self-hosted-ai-assistant-kept-overwriting-its-own-api-keys-a-zero-trust.jsonld"}}