-
-
Notifications
You must be signed in to change notification settings - Fork 69.6k
[Bug]: [Security] [2026.3.8]Heartbeat-triggered agent activation persists custom provider API key as plaintext in agent-local models.json #42355
Description
Bug type
Behavior bug (incorrect output/state without crash)
Summary
On OpenClaw 2026.3.8, a custom OpenAI-compatible provider backed by an environment variable can still be materialized into plaintext inside agent-local models.json.
In my deployment, the first system-triggered heartbeat activation of agent chempro created:
- a
mainsession for that agent withsystemSent: trueandprovider: heartbeat - an agent-local
models.json
That models.json persisted the custom provider API key as a resolved plaintext value.
By contrast, other agents that later generated models.json through different activation paths only stored the environment variable name (LLM_API_KEY) rather than the resolved secret value.
So the issue appears to be path-dependent:
- heartbeat/system auto-activation path → writes resolved plaintext API key
- other activation paths → writes env var marker only
This looks like an incomplete fix for the previously reported SecretRef/custom-provider persistence bug.
Version
- OpenClaw:
2026.3.8 (3caab92)
Environment
- Debian 12 in PVE LXC
- Gateway running as systemd service
- Multi-agent setup
- Custom OpenAI-compatible provider using Volcengine Ark endpoint:
https://ark.cn-beijing.volces.com/api/v3
- API key configured via environment variable / SecretRef path
models.mode: "merge"
Steps to reproduce
- Configure the custom provider in
openclaw.jsonwith env/SecretRef-backedapiKey. - Start the gateway.
- Do not send any Telegram message to
chempro. - Wait for the system heartbeat / auto-activation path.
- Check:
cat /opt/openclaw/state/agents/chempro/sessions/sessions.json sed -n '1,120p' /opt/openclaw/state/agents/chempro/agent/models.json - Observe that:
• sessions.json shows a system-created heartbeat session:
• systemSent: true
• origin.provider: "heartbeat"
• deliveryContext.to: "heartbeat"
• chempro/agent/models.json is created
• apiKey is persisted as a resolved plaintext secret
Comparison
Other agents later generated models.json too, but their files stored only the env var name:
"apiKey": "LLM_API_KEY"
while chempro/agent/models.json stored:
"apiKey": "<REDACTED_PLAINTEXT_SECRET>"
Expected behavior
For custom providers whose API key originates from env / SecretRef, agent-local models.json should never persist the resolved secret value as plaintext.
At most, the file should contain:
- a source marker
- an env var identifier (for example
LLM_API_KEY) - or some non-secret placeholder
It should not write the actual API key to disk.
Actual behavior
A system-generated heartbeat activation for chempro created:
sessions.jsonentry showing a heartbeat-originated system sessionagent/models.jsoncontaining a resolved plaintext API key
At the same time, other agents generated models.json files that referenced the same provider but did not persist the resolved key; they stored LLM_API_KEY instead.
This inconsistency suggests the secret handling differs depending on activation path.
OpenClaw version
2026.3.8
Operating system
Debian12
Install method
npm global
Model
OpenAI-compatible
Provider / routing chain
openclaw -> volcano engine -> doubao-seed-2-0-pro-260215
Config file / key location
No response
Additional provider/model setup details
No response
Logs, screenshots, and evidence
Impact and severity
No response
Additional information
No response