Here's a pattern that has quietly become normal in a lot of companies.
An operations person gets tired of copying data between the CRM and the accounting system by hand. They spin up n8n — self-hosted, in Docker, on their work laptop or on a spare VM under someone's desk. They paste in live credentials: the database, the CRM API, the payment provider, the 1C instance. It works. It saves them four hours a week. They tell two colleagues, who do the same.
Nobody in security knows this exists. There is now an unmanaged automation platform holding production credentials, running on an endpoint with no monitoring, whose failure mode is "the intern's laptop was stolen."
The uncomfortable part is that your existing tools genuinely can't see it.
Why the existing tools miss it
SaaS discovery tools (Defender for Cloud Apps, Nudge, Auvik and friends) discover OAuth grants and cloud apps. A self-hosted n8n on localhost:5678 grants nothing through OAuth — it holds credentials directly.
EDR sees a Node.js process. It's not wrong. It's just that "node is running" is not an actionable finding, and the EDR has no concept of "this process holds a credential that reaches the payment API."
Network monitoring sees traffic from a workstation to your own database. That's traffic it's supposed to see.
Each tool is working correctly. The blind spot is between them: nobody maps unmanaged automation instance → the credentials it holds → the production systems those credentials reach. That map is the finding. Everything else is noise.
So I built AutoGov to produce exactly that map.
Detection has to be multi-signal, or it's useless
The naive version — "port 5678 is open, alert!" — generates so many false positives that people turn it off in a week. Detection here combines signals and never fires on one alone:
| Signal | What it inspects |
|---|---|
| Docker |
n8nio/n8n images, port 5678, N8N_* env vars, linked postgres/redis (queue mode) — via a read-only socket |
| Processes | Node.js n8n signatures, Python runners and schedulers in /proc
|
| Network | HTTP fingerprint: /rest + /api/v1/docs + /healthz together uniquely identify n8n |
| Filesystem |
~/.n8n, a docker-compose.yml mentioning n8n, .env files referencing N8N_ENCRYPTION_KEY
|
| Schedulers |
cron entries and systemd timers launching automation runners |
Sanctioned instances go on a whitelist, so CI/CD containers don't generate a daily alert. That was a first-release requirement rather than a "later" item — a security tool that cries wolf gets muted, and a muted tool is worse than no tool because it creates the illusion of coverage.
The privacy problem, and the design that solves it
A tool that hunts for credentials on employee machines is itself a serious risk. If it collects secret values, you have built a company-wide credential exfiltration system and pointed it at yourself. One compromised control plane and the attacker gets everything at once.
So the agent records the fact that a secret exists — its name, its type, the system it targets — plus a SHA-256 fingerprint for correlation. It never reads or transmits the value. This isn't a policy or a code review rule: no field in the data model can hold a secret or PII. You can't misconfigure your way into collecting them, because there's nowhere to put them.
The rest of the security posture follows the same logic:
- The agent is outbound-only and opens no listening ports — it can't become a new attack surface on the endpoints it's installed on.
- The Docker socket is mounted read-only. Discovery needs to read container metadata; it never needs to start, stop or exec into anything.
- Release artifacts are ed25519-signed and verified by the agent at startup, fail-closed. An agent that runs everywhere with root-adjacent visibility is a supply-chain target, and it should refuse to run unsigned code.
- mTLS between agent and control plane, RBAC and an audit log on top.
What you actually see
For each discovered instance: which credentials it holds, which production systems those credentials reach, a numeric risk score, a Critical/High/Medium/Low category, and a plain-language explanation of why it scored that way — generated locally, with no LLM in the loop, because a CISO report needs to be reproducible and defensible rather than eloquent.
That access map is the artifact that turns "there is unmanaged software here" into "this laptop can move money."
Two-minute demo
The compose file brings up the control plane, an intentionally shadow n8n instance, and an agent — so you can watch discovery happen on a system that's deliberately misconfigured:
git clone https://github.com/oleg-vdv/AutoGov.git
cd AutoGov/deploy
docker compose up --build
Open http://localhost:8443, log in with the token dev-admin, and within about 30 seconds the agent finds the instance, builds the access map, and shows risk-scored findings. (Demo uses HTTP and dev tokens — local evaluation only.)
Building from source:
make build # → bin/agent, bin/controlplane, bin/autogov-sign
make test
Pure Go standard library, no external dependencies — which keeps the agent auditable and makes air-gapped installs boring, in the good way.
Current state
Stage 1 (n8n discovery) is MVP and pilot-ready. Generic automations — Make agents, ad-hoc scripts, a Windows agent — are next, with module contracts and stubs already in place for the later stages: honeypot nodes, self-healing and auto-documentation. The module runtime lets those plug in without touching the core, which the tests enforce.
Apache 2.0: https://github.com/oleg-vdv/AutoGov
If you've dealt with shadow automation in your own organization, I'd like to know how you found it — and whether you tried to shut it down or bring it under management. My assumption is that shutting it down mostly fails, because the four hours a week were real, but I'd be glad to hear counterexamples.
Top comments (0)