Fail closed when an explicit agent harness is missing#71265
Fail closed when an explicit agent harness is missing#71265pashpashpash merged 2 commits intomainfrom
Conversation
Greptile SummaryThis PR changes the default fallback behavior for the embedded agent harness: Confidence Score: 5/5Safe to merge — the logic change is minimal, well-tested, and backwards compatible for All findings are P2 or lower. The core logic in No files require special attention. Reviews (1): Last reviewed commit: "Fail closed for explicit agent harness s..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ade8e4bde0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
1. 🔵 Log/CRLF injection via unvalidated OPENCLAW_AGENT_RUNTIME included in error message
DescriptionThe agent harness runtime can be sourced from When a non-registered runtime is forced and PI fallback is disabled, the runtime string is interpolated directly into a thrown error message:
If the resulting Vulnerable code: if (policy.fallback === "none") {
throw new Error(
`Requested agent harness "${runtime}" is not registered and PI fallback is disabled.`,
);
}RecommendationConstrain plugin runtime ids to a safe character set/length at normalization time (or before use in logs/errors) and reject invalid values. For example: const RUNTIME_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
export function normalizeEmbeddedAgentRuntime(raw: string | undefined): EmbeddedAgentRuntime {
const value = raw?.trim();
if (!value) return "auto";
if (value === "pi" || value === "auto") return value;
if (!RUNTIME_ID_RE.test(value)) {
throw new Error("Invalid agent runtime id");
}
return value;
}Additionally, when embedding identifiers into human-readable log/error strings, consider escaping control characters (e.g., replacing 2. 🔵 Invalid OPENCLAW_AGENT_HARNESS_FALLBACK values are silently ignored, potentially re-enabling PI fallback
Description
Impact:
Vulnerable behavior: const raw = env.OPENCLAW_AGENT_HARNESS_FALLBACK?.trim().toLowerCase();
if (raw === "pi" || raw === "none") {
return raw;
}
return undefined; // invalid values are ignoredThis is a fail-open behavior from a security-policy perspective: invalid policy input results in default behavior (which may allow PI fallback) rather than a hard failure or explicit warning. RecommendationTreat an explicitly-provided but invalid Options:
export function resolveEmbeddedAgentHarnessFallback(
env: NodeJS.ProcessEnv = process.env,
): EmbeddedAgentHarnessFallback | undefined {
const raw = env.OPENCLAW_AGENT_HARNESS_FALLBACK;
if (raw == null) return undefined;
const normalized = raw.trim().toLowerCase();
if (normalized === "pi" || normalized === "none") return normalized;
throw new Error(
`Invalid OPENCLAW_AGENT_HARNESS_FALLBACK=${JSON.stringify(raw)} (expected "pi" or "none")`,
);
}
Analyzed PR: #71265 at commit Last updated on: 2026-04-24T21:35:59Z |
* Fail closed for explicit agent harness selection * Scope explicit harness fallback opt in
* Fail closed for explicit agent harness selection * Scope explicit harness fallback opt in
* Fail closed for explicit agent harness selection * Scope explicit harness fallback opt in
OpenClaw already stopped falling back to PI after a selected Codex harness fails. The remaining confusing case was earlier in the flow: if someone explicitly asked for a concrete harness like
codex, but that harness was not registered, omitted fallback config still meant PI could silently take the turn.This changes the default fallback based on intent.
runtime: "auto"keeps the compatibility behavior and still defaults to PI when no plugin harness claims the run. An explicit plugin runtime now defaults to no PI fallback, soruntime: "codex"means Codex or a clear failure unless the user deliberately setsfallback: "pi".The docs and generated config help now describe that split, and the harness selection tests cover env-forced and config-forced Codex selection both with omitted fallback and explicit PI fallback.