Agent Security¶
Annolid includes agent security checks for local state, channel exposure, session routing, tool policy risk, and signature enforcement.
Use this page together with Agent Secrets when hardening a local or shared Annolid agent deployment.
Commands¶
Primary security commands:
annolid-run agent-security-check
annolid-run agent-security-audit
annolid-run agent-security-audit --fix
annolid-run agent-secrets-audit
Operator-style aliases are also supported:
annolid-run agent security audit
annolid-run agent security audit --fix
What Each Command Does¶
annolid-run agent-security-check¶
Runs a focused configuration hygiene check. It reports:
- plaintext secrets in persisted LLM settings,
- plaintext agent secrets in
~/.annolid/config.json, - unresolved secret refs,
- local file permission problems for security-sensitive files.
Use this when you want a quick health check for credentials and private file modes.
annolid-run agent-security-audit¶
Runs a broader posture audit across the agent configuration. It inspects:
- secret hygiene,
config.json, secret-store, and sessions directory permissions,- DM session scope safety for shared messaging channels,
- missing channel allowlists,
- disabled runtime tool guard rails,
- risky tool-policy combinations,
- unsigned skill-install and auto-update exposure.
This command exits with a warning status when findings are present.
annolid-run agent-security-audit --fix¶
Applies only safe local permission repairs. It can tighten modes for:
- the agent config directory,
~/.annolid/config.json,~/.annolid/agent_secrets.json,- the local sessions directory.
It does not automatically:
- change session-routing policy,
- rewrite tool allow/deny policy,
- disable channels,
- migrate secrets,
- change update/signature policy.
Those changes are intentionally left for explicit operator review.
What the Audit Flags¶
Plaintext Secrets¶
The audit reports plaintext secrets still stored in ~/.annolid/config.json.
Recommended action:
annolid-run agent-secrets-migrate
annolid-run agent-secrets-migrate --apply
Or attach explicit refs:
annolid-run agent-secrets-set --path tools.zulip.api_key --env ZULIP_API_KEY
For a WhatsApp Cloud API webhook, store the Meta app secret through a ref:
annolid-run agent-secrets-set \
--path tools.whatsapp.app_secret \
--env WHATSAPP_APP_SECRET
Unresolved Secret Refs¶
If a secret ref exists but its environment variable or local-store value is missing, the audit reports it as unresolved.
Recommended action:
- populate the required environment variable, or
- write the secret to the local secret store and attach a
localref.
Unsafe DM Session Scope¶
If external channels such as Zulip, WhatsApp, or email are enabled while DM session scope is main, the audit flags it.
Why this matters:
maincan collapse independent DM conversations into the same session state,- shared inbox or multi-user messaging setups can leak conversation context across senders.
Recommended action:
- prefer
per-account-channel-peerfor shared messaging environments, - otherwise use
per-peerorper-channel-peerdepending on the channel design.
Empty Channel Allowlists¶
If an external channel is enabled and allow_from is empty, the audit flags it.
Why this matters:
- the channel may accept inbound messages from any sender the integration can see.
Recommended action:
- explicitly populate
allow_fromwith trusted senders or accounts before using the integration in production.
Disabled Runtime Guard¶
If agents.defaults.strict_runtime_tool_guard is disabled, the audit flags it.
Why this matters:
- Annolid has deny-by-default runtime protections for combinations such as shell execution plus messaging or automation primitives.
- disabling the guard removes a key safety backstop if policy is too broad.
Recommended action:
- re-enable
strict_runtime_tool_guardunless the deployment has a narrow, reviewed exception.
Risky Tool Policy Combinations¶
The audit looks for high-risk requested policy shapes, especially when runtime guard rails are disabled.
Examples:
- process execution plus email/message/automation tools,
- process execution plus broad web/browser tooling,
- skill installation without signed-skill enforcement.
Recommended action:
- split broad profiles into narrower task-specific profiles,
- keep runtime execution separate from messaging and scheduling where possible,
- require signed skills in production-like environments.
Runtime Network and Workspace Guards¶
Annolid Bot blocks shell commands that target private or internal HTTP(S)
addresses, including local hosts and cloud metadata ranges. Workspace-scoped
shell execution also treats the configured workspace as the trusted root, so a
tool call cannot widen access by passing a different working_dir.
Agent web-search, web-fetch, and download clients apply the same public-target validation to every outgoing request, including each redirect hop. Redirect targets that resolve to localhost, private networks, or cloud metadata services are rejected before the redirected request is sent. URLs containing embedded credentials, control characters, ambiguous backslashes, or invalid ports are also rejected. The validated public DNS result is pinned to the actual HTTP connection to prevent DNS rebinding between validation and connect. Environment proxies are disabled for these requests because a proxy would resolve the destination outside Annolid's pinned connection boundary.
Keyless web search uses the DDGS client against its fixed search providers, so
the user controls the query but not the request destination. Search-result URLs
are syntax-checked before they are returned. The hardened DuckDuckGo HTML and
optional Brave fallbacks use Annolid's pinned HTTP client; the legacy
scrapling backend name remains as a compatibility alias. Search and fetched
page text are explicitly labeled as untrusted external content before they are
returned to a model. Fetch responses are streamed with a hard byte limit and
binary content must use download_url.
Downloads accept only a narrow set of representation and conditional request headers; credentials, cookies, proxy headers, and host overrides are refused. The configured download-size ceiling cannot be raised by a tool call. Files are downloaded to a same-directory temporary file and atomically installed only after validation succeeds, so a failed replacement does not destroy an existing destination.
Agent-requested GUI URLs use the same public-target validation. Local files can be opened only when they resolve inside the configured workspace or read roots.
Workspace restriction is enabled by default. Annolid does not register the host-backed
exec_start and exec_process tools. The Docker-backed exec tool also fails
closed when Docker is unavailable instead of silently falling back to the host.
Shell guards also inspect absolute paths after option separators such as
--output=/outside/path.
The default Docker image is pinned to a reviewed immutable SHA-256 digest.
Floating image tags are refused at execution time and reported by
agent-security-audit. Existing configurations can explicitly set
tools.restrict_to_workspace=false, but doing so re-enables host-backed managed
shell sessions and is reported as a high-severity finding.
Filesystem tools report workspace-boundary failures as hard policy boundaries. If the same outside target is retried across equivalent tools, the tool registry returns a refusal that tells the agent to ask the user how to proceed instead of trying shell or path-workaround variants.
Text read/edit tools reject files larger than 100 MiB before loading them into memory. Use a format-specific or streaming workflow for larger artifacts.
WhatsApp Webhook Authentication¶
When tools.whatsapp.app_secret is configured, POST requests must carry a valid
Meta X-Hub-Signature-256 signature over the exact request body. Invalid or
missing signatures are rejected before the payload reaches the message bus.
Annolid refuses to start an unsigned listener, including on loopback. This prevents another local process or a browser-originated cross-site request from injecting a message into the agent. Configure the app secret before enabling the webhook or forwarding it through a public HTTPS tunnel.
Outbound WhatsApp Cloud API calls also require an HTTPS, publicly resolvable
graph.facebook.com endpoint before Annolid attaches the access token.
Unsigned Auto Updates¶
If automatic updates are enabled without strict signature requirements, the audit flags it.
Recommended action:
- enable signature enforcement in both config and environment before using automatic updates in production.
Files and Permissions¶
Security-sensitive local paths:
- agent config:
~/.annolid/config.json - local secret store:
~/.annolid/agent_secrets.json - sessions dir:
~/.annolid/sessions/
Recommended modes:
- directories:
700 - files:
600
annolid-run agent-security-audit --fix can repair these modes when the files are writable by the current user.
Recommended Hardening Flow¶
For a local but security-conscious setup:
annolid-run agent-secrets-audit
annolid-run agent-secrets-migrate --apply
annolid-run agent-security-check
annolid-run agent-security-audit
If the audit reports only permission issues:
annolid-run agent-security-audit --fix
Then re-run:
annolid-run agent-security-audit
Example Operator Review¶
Typical findings worth fixing before enabling shared messaging:
plaintext-config-secretsdm-scope-mainchannel-allowlist-zulipstrict-runtime-tool-guard-disabledunsigned-auto-update
The audit output is JSON so it can be inspected manually or consumed by scripts.
Notes¶
- The security audit is intentionally additive and does not break backward compatibility.
--fixis deliberately conservative and only changes local file permissions.- Secret hygiene is documented in more detail on Agent Secrets.