openclawshadow-itnhisecurityai-agents

Detecting Shadow OpenClaw Agents in Your Organisation

Someone in your engineering org has spun up an OpenClaw agent with a personal CLI token. Here's how to detect it within minutes — not at the next audit.

secr team·

Every NHI program eventually faces the same uncomfortable question: how many automated actors are running against our systems that we don't know about?

For OpenClaw specifically, the answer is "more than you think." OpenClaw is easy to install, easy to point at credentials, and easy to deploy to a Render service or a teammate's laptop. The official deploy path is paved; the unofficial one — "use your personal CLI token, paste it into IDENTITY.md, and run it on a VM" — is even easier.

This post is about catching the second kind. The mechanism is shadow agent detection: server-side fingerprinting that flags any human credential being used by what looks like an OpenClaw agent.

The shadow-agent pattern

Here's how it usually plays out:

  1. A developer wants to try OpenClaw against your production environment.
  2. They have a personal secr_tok_* CLI token (or a session cookie from a browser login).
  3. The proper path is to create a scoped secr_agent_* identity, but that requires admin permission.
  4. Instead, they paste their personal token into IDENTITY.md or an environment variable on a Render service.
  5. OpenClaw runs. It works. Nobody notices.

From the secr API's point of view, this looks like normal human traffic — except the User-Agent header reads openclaw/1.2.3 or OpenClaw-Agent/0.5 instead of secr-cli/1.0 or a browser string. That's the signal.

Fingerprinting

The shadow-agent detector runs on every authenticated request that uses a CLI token or a session cookie (not on secr_agent_* traffic — those are already identified as agents, by definition). The check:

  1. Read the User-Agent header.
  2. Match it against KNOWN_AI_AGENTS — a curated list including openclaw*, *openclaw*, moltbot*, claude*, cursor*, *copilot*, aider*, and others.
  3. If matched, compute a fingerprint: SHA-256(userAgent::tokenType::tokenId).
  4. Insert (or update) a row in shadow_agents with the matched name, vendor, and framework slugopenclaw for the OpenClaw family.
  5. If it's a new fingerprint, also insert an nhi_anomalies row at severity high and dispatch a nhi.shadow_agent webhook.

Each subsequent request from the same fingerprint increments accessCount, merges new source IPs, and recomputes a risk level (low / medium / high) based on volume and IP/project diversity.

What the dashboard shows

In /dashboard/nhi/shadow-agents, each detected entry renders with:

  • The matched agent name (OpenClaw)
  • The vendor (OpenClaw)
  • A coloured framework badge — for OpenClaw specifically, this is a warning-amber pill, distinct from the neutral pills for Claude Code, Cursor, etc.
  • Risk level (low / medium / high)
  • Status (active / dismissed / resolved)
  • Source IPs, access count, last seen
  • Token type (cli_token or session) and the human owner

The framework badge is what makes OpenClaw stand out at a glance. If a manager scans the page weekly, they don't have to read user-agent strings to spot the OpenClaw deployments — they just look for the amber pills.

What you do with a detection

Three options for each entry:

Resolve

This is the right answer when the agent should exist — someone genuinely needs an OpenClaw deployment, they just used the wrong credential. You:

  1. Have them create a proper secr_agent_* identity with project/environment/allowlist scoping.
  2. In the dashboard, click Resolve and link the shadow row to the new agent identity.
  3. The shadow row's status becomes resolved with a back-reference, so the audit trail is preserved.

Dismiss

The agent is known and safe but doesn't need a separate identity (rare for OpenClaw). Click Dismiss with a note. The status becomes dismissed. It stops appearing in the active list but stays in the audit history.

Investigate, then revoke

The agent is unauthorised. The action is on the credential, not the shadow row:

  1. Find the human owner of the cli_token or session.
  2. Have a conversation about what their OpenClaw agent is doing.
  3. Revoke the credential they used (secr token revoke).
  4. The shadow row stays in the historical record.

The dashboard's Risk column helps prioritise: a row with risk=high (50+ accesses, multiple IPs, multiple projects) is a "this week" task; risk=low is a "next sprint" task.

The OpenClaw posture rule

Beyond detection, the compliance report has a specific rule for OpenClaw agents that are registered but lack proper scoping:

"OpenClaw-fingerprinted agent support-bot is missing scoping (projectId, secretAllowlist); recreate with --project, --env, and --allowlist"

This fires when:

  1. There's a registered secr_agent_* identity (so it's not a shadow agent, just a known agent)
  2. The nhi_baselines.knownUserAgents for that agent contains an OpenClaw-pattern string (so it's being used by an OpenClaw deployment)
  3. The agent is missing one of: projectId, environmentId, secretAllowlist

This is the post-shadow-detection insight: even your managed OpenClaw agents should have all three scope fields. The full posture story is in the NHI posture checklist.

Tuning detection

A few practical notes from running this in real deployments:

False positives are rare but possible

The KNOWN_AI_AGENTS list is conservative. If your team has a service that legitimately calls itself openclaw-internal-tool, the detector will flag it. Two fixes:

  • Rename it to something that doesn't match the patterns
  • Or accept the detection and dismiss the entries with a note

Detection runs fire-and-forget

The check is async to keep the request path fast. If your test environment runs the detector against truncated tables, expect a brief gap before the row appears (usually < 500ms). The await new Promise(r => setTimeout(r, 500)) pattern in tests covers this.

Deletion of the underlying user cascades

If a human user is deleted, their shadow rows are deleted too (onDelete: cascade on userId). The audit log still has the original events; you just lose the aggregated shadow view. If you need to preserve the shadow rows after offboarding, dismiss them explicitly first.

The framework column is forward-compatible

Today, framework is openclaw, claude-code, or null. As we identify more autonomous-agent frameworks, that list grows. The schema doesn't need to change; the detector is data-driven from KNOWN_AI_AGENTS.

What it costs to leave on

Effectively zero. The detection check is one regex match plus one DB upsert per matched request. Total p99 added latency is sub-millisecond. The webhook dispatch is fire-and-forget. There's no batch job, no pollers, no daemon to maintain.

The only ongoing cost is reviewing the dashboard. Once a week, scan the active shadow agents, resolve / dismiss / investigate, and move on.

The closing point

You can't govern what you can't see. Shadow agent detection turns "we don't know what OpenClaw deployments exist in our org" into "we have an active list of every OpenClaw deployment, the credential it's using, and the risk it represents."

That's the first half of NHI for AI agents. The second half is making sure the managed agents are configured correctly — see the posture checklist for that.


Next: The OpenClaw NHI posture checklist — the full posture rules with remediation for each.


The OpenClaw plugin (@secr/openclaw-plugin) is on ClawHub and free for 1 agent. Install reference → · The /agents pillar · Approve tool calls from Telegram · Approval webhooks

Ready to get started?

Stop sharing secrets over Slack. Get set up in under two minutes.

Create your account