openclaw - 💡(How to fix) Fix [Bug]: models.json generator writes apiKey as plain string instead of secret-ref object [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

The derived per-agent models.json generator resolves auth-profile keyRef entries and writes the apiKey field as a plain string ("apiKey": "***") instead of using the structured secret-reference object ({"source": "env", "provider": "default", "id": "TENSORIX_API_KEY"}). This triggers the openclaw security audit --deep PLAINTEXT_FOUND warning because the env-var name looks like a plaintext credential.

Root Cause

Summary

The derived per-agent models.json generator resolves auth-profile keyRef entries and writes the apiKey field as a plain string ("apiKey": "***") instead of using the structured secret-reference object ({"source": "env", "provider": "default", "id": "TENSORIX_API_KEY"}). This triggers the openclaw security audit --deep PLAINTEXT_FOUND warning because the env-var name looks like a plaintext credential.

Fix Action

Fixed

Code Example

cat ~/.openclaw/agents/main/agent/models.json | jq '.providers.tensorix.apiKey'
# => "TENSORIX_API_KEY" (or "***")

---

"apiKey": {
  "source": "env",
  "provider": "default",
  "id": "TENSORIX_API_KEY"
}

---

"apiKey": "TENSORIX_API_KEY"

---

"tensorix:default": {
  "type": "api_key",
  "provider": "tensorix",
  "keyRef": {
    "source": "env",
    "provider": "default",
    "id": "TENSORIX_API_KEY"
  }
}

---

"tensorix": {
  "api": "openai-completions",
  "apiKey": "TENSORIX_API_KEY",
  ...
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

The derived per-agent models.json generator resolves auth-profile keyRef entries and writes the apiKey field as a plain string ("apiKey": "***") instead of using the structured secret-reference object ({"source": "env", "provider": "default", "id": "TENSORIX_API_KEY"}). This triggers the openclaw security audit --deep PLAINTEXT_FOUND warning because the env-var name looks like a plaintext credential.

Steps to reproduce

  1. Configure a custom provider (e.g. tensorix proxy) in models.providers with an auth profile using env-var keyRef.
  2. Set that provider's model as the default agent's primary model.
  3. Run openclaw security audit --deep.
  4. Observe PLAINTEXT_FOUND warning pointing at agents/*/agent/models.json.

Or inspect directly:

cat ~/.openclaw/agents/main/agent/models.json | jq '.providers.tensorix.apiKey'
# => "TENSORIX_API_KEY" (or "***")

Expected behavior

The apiKey field in the derived models.json should use the same structured secret-reference format as the source auth-profiles.json:

"apiKey": {
  "source": "env",
  "provider": "default",
  "id": "TENSORIX_API_KEY"
}

This would not trigger the plaintext audit warning since the security scanner recognizes this structure.

Actual behavior

The generator resolves the keyRef to the env-var name string and writes it as a bare string value:

"apiKey": "TENSORIX_API_KEY"

The security audit correctly flags this as plaintext.

OpenClaw version

2026.5.28 (e932160)

Operating system

Linux 6.8.0-124-generic (Ubuntu 24.04)

Install method

npm global

Model

tensorix/deepseek/deepseek-v4-pro

Provider / routing chain

openclaw -> tensorix proxy (api.tensorix.ai)

Additional provider/model setup details

Provider configured in models.providers.tensorix with api: openai-completions. Auth profile tensorix:default in auth.profiles uses api_key mode. The keyRef in auth-profiles.json is correct — the plaintext issue is only in the derived models.json.

Additional findings from investigation

  • models.json generation is lazy/on-demand per agent, not a blanket restart action. Only the default agent gets startup warmup generation.
  • Stale agent models.json files are not cleaned up on restart (e.g. vitruvius agent retained a May 23 copy with 146 eurouter models until next demand-driven regeneration).
  • The fingerprint cache can keep stale files alive across restarts if the cache key still matches.
  • Agents that have never triggered a model resolution (e.g. praevidus) never get a models.json file at all — yet they still function correctly, suggesting the file may be unnecessary for agents that use globally-configured providers.

Impact and severity

  • Affected: any operator running openclaw security audit --deep with env-var-based provider auth
  • Severity: Low (cosmetic — the real secret is never written to disk, only the env var name)
  • Frequency: always on regeneration
  • Consequence: false-positive audit warning, potential compliance noise

Logs, screenshots, and evidence

Source auth-profiles.json (correct):

"tensorix:default": {
  "type": "api_key",
  "provider": "tensorix",
  "keyRef": {
    "source": "env",
    "provider": "default",
    "id": "TENSORIX_API_KEY"
  }
}

Derived models.json (incorrect — string instead of object):

"tensorix": {
  "api": "openai-completions",
  "apiKey": "TENSORIX_API_KEY",
  ...
}

Audit output:

[PLAINTEXT_FOUND] /home/mnowrot/.openclaw/agents/main/agent/models.json:providers.tensorix.apiKey models.json

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The apiKey field in the derived models.json should use the same structured secret-reference format as the source auth-profiles.json:

"apiKey": {
  "source": "env",
  "provider": "default",
  "id": "TENSORIX_API_KEY"
}

This would not trigger the plaintext audit warning since the security scanner recognizes this structure.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: models.json generator writes apiKey as plain string instead of secret-ref object [1 pull requests]