fix: resolve local TTS SecretRefs before conversion#72549
Conversation
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟠 Potential arbitrary command execution via SecretRef exec provider during `infer tts convert` secret resolution
Description
If the gateway is unavailable or its snapshot is incomplete, Why this is a security risk:
This can lead to executing attacker-controlled binaries/scripts referenced in config (e.g., an RecommendationTreat Suggested mitigations (pick one or combine):
await resolveCommandSecretRefsViaGateway({
config: loadConfig(),
commandName: "infer tts convert",
targetIds: getTtsCommandSecretTargetIds(),
mode: "enforce_resolved",
// new option: disallowLocalExecProviders: true
});
if (providerConfig.source === "exec") {
throw new Error("Exec secret providers are disabled for this command unless --allow-exec-secrets is set");
}
Analyzed PR: #72549 at commit Last updated on: 2026-04-27T03:19:04Z |
Greptile SummaryRoutes local Confidence Score: 5/5This PR is safe to merge — the fix is narrow, well-tested, and follows the existing SecretRef resolution pattern used by other command paths. Changes are tightly scoped: a single call-site switch from No files require special attention. Reviews (1): Last reviewed commit: "fix: resolve tts secret refs for local i..." | Re-trigger Greptile |
This reverts commit 4878d3e.
This reverts commit 6506f23.
This reverts commit f89ac65.
This reverts commit 28461ca.
This reverts commit 0884f7b.
This reverts commit d37ad37.
This reverts commit 01282ec.
Summary
infer tts convertloaded source config directly, somessages.tts.providers.minimax.apiKeystayed as a SecretRef object instead of the resolved startup/reload snapshot value.messages.tts.providers.*.apiKeybefore computing TTS overrides and calling the runtime.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
loadConfig()directly, while SecretRef-backed command paths need the shared command SecretRef resolver to read the active gateway snapshot or local fallback resolution.src/cli/capability-cli.tswas not listed in command SecretRef resolution callsite coverage.apiKeythrough normalized resolved secret input and fails when it receives an unresolved SecretRef object.Regression Test Plan (if applicable)
src/cli/capability-cli.test.ts,src/cli/command-secret-resolution.coverage.test.ts,src/cli/command-secret-targets.test.tscapability tts convertresolvesmessages.tts.providers.*.apiKeySecretRefs and passes the resolved config to TTS override/runtime code.User-visible / Behavior Changes
Local
openclaw infer tts convertnow supports SecretRef-backedmessages.tts.providers.minimax.apiKeythrough the shared command SecretRef resolution path.Diagram (if applicable)
Security Impact (required)
Yes/No) NoYes/No) YesYes/No) NoYes/No) NoYes/No) NoYes, explain risk + mitigation: local TTS now uses the same command SecretRef resolver already used by other supported command paths, scoped only to static TTS provider API-key targets andenforce_resolvedmode.Repro + Verification
Environment
node:22-bookwormmessages.tts.provider: "minimax";messages.tts.providers.minimax.apiKeyas an exec SecretRef resolving to a mock static keySteps
messages.tts.providers.minimax.apiKeyas an exec SecretRef and point MiniMax TTSbaseUrlto a local mock endpoint.OPENCLAW_STATE_DIR=/workspace/repro/state pnpm openclaw secrets audit --allow-exec --json.OPENCLAW_STATE_DIR=/workspace/repro/state pnpm openclaw infer tts convert --text "SecretRef reproduction sample" --json.OPENCLAW_STATE_DIR=/workspace/repro/state pnpm openclaw infer tts convert --text "SecretRef explicit MiniMax sample" --model minimax/speech-2.8-hd --json.Expected
Actual
provider: "minimax".Evidence
Docker mock endpoint received two requests with
Authorization: Bearer mock-minimax-static-keyafter the fix.Local validation:
pnpm test src/cli/capability-cli.test.ts src/cli/command-secret-targets.test.ts src/cli/command-secret-targets.import.test.ts src/cli/command-secret-resolution.coverage.test.tspnpm check:changedHuman Verification (required)
Review Conversations
Compatibility / Migration
Yes/No) YesYes/No) NoYes/No) NoRisks and Mitigations
messages.tts.providers.*.apiKeyand uses the existing shared resolver withenforce_resolvedbehavior.