fix(dotenv): block Windows shell trust-root vars from workspace .env [AI-assisted] (#74460)

* fix: address issue

* fix: address PR review feedback

* changelog: PR #74460

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
This commit is contained in:
Michael Appel
2026-05-01 15:59:47 -04:00
committed by GitHub
parent e1732c2757
commit b56bb9f43d
3 changed files with 43 additions and 0 deletions

View File

@@ -163,6 +163,7 @@ Docs: https://docs.openclaw.ai
- Agents/failover: carry `sessionId`, `lane`, `provider`, `model`, and `profileId` attribution through `FailoverError` and `describeFailoverError`/`coerceToFailoverError` so structured error logs (e.g. `gateway.err.log` ingestion) can attribute exhausted-fallback wrapper errors to the originating session and last-attempted provider instead of dropping the metadata after the per-profile errors. Fixes #42713. (#73506) Thanks @wenxu007.
- Context Engine: treat assembled prompt as the default authority for preemptive overflow prechecks so engines that return a windowed, self-contained context no longer trigger false hard-fail compactions on huge raw history. Engines whose assembled view can hide overflow risk can opt back into the legacy behavior with `AssembleResult.promptAuthority: "preassembly_may_overflow"`. (#74255) Thanks @100yenadmin.
- Mattermost: refresh current native slash command registrations before accepting callbacks so stale tokens from deleted or regenerated commands stop being accepted without a gateway restart while failed validations stay briefly cached and lookup starts are rate-limited per command, gate each callback against the resolved command's own startup token so a token leaked for one slash command cannot poison another command's failure cache, redact slash validation lookup errors, and add a body read timeout to the multi-account routing path so slow callback senders cannot tie up the dispatcher. Thanks @feynman-hou and @eleqtrizit.
- Security/dotenv: block `COMSPEC` in workspace `.env` so a malicious repo cannot redirect Windows `cmd.exe` resolution, and lock in case-insensitive workspace-`.env` regression coverage for the full Windows shell trust-root family (`COMSPEC`, `PROGRAMFILES`, `PROGRAMW6432`, `SYSTEMROOT`, `WINDIR`). (#74460) Thanks @mmaps.
## 2026.4.29

View File

@@ -41,6 +41,19 @@ const BUNDLED_TRUST_ROOT_ENV_KEYS = BUNDLED_TRUST_ROOT_ENV_LINES.map(
(line) => line.split("=")[0] ?? "",
);
const WINDOWS_SHELL_TRUST_ROOT_ENV_KEYS = [
"ComSpec",
"COMSPEC",
"ProgramFiles",
"PROGRAMFILES",
"ProgramW6432",
"PROGRAMW6432",
"SystemRoot",
"SYSTEMROOT",
"windir",
"WINDIR",
] as const;
async function writeEnvFile(filePath: string, contents: string) {
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, contents, "utf8");
@@ -305,6 +318,34 @@ describe("loadDotEnv", () => {
});
});
it("blocks Windows shell trust-root vars from workspace .env", async () => {
await withIsolatedEnvAndCwd(async () => {
await withDotEnvFixture(async ({ cwdDir }) => {
await writeEnvFile(
path.join(cwdDir, ".env"),
[
"ComSpec=.\\evil-comspec",
"COMSPEC=.\\evil-comspec-upper",
"ProgramFiles=.\\evil-pfiles",
"PROGRAMFILES=.\\evil-pfiles-upper",
"ProgramW6432=.\\evil-pw6432",
"PROGRAMW6432=.\\evil-pw6432-upper",
"SystemRoot=.\\fake-root",
"SYSTEMROOT=.\\fake-root-upper",
"windir=.\\fake-windir",
"WINDIR=.\\fake-windir-upper",
].join("\n"),
);
clearEnv(WINDOWS_SHELL_TRUST_ROOT_ENV_KEYS);
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
expectEnvUndefined(WINDOWS_SHELL_TRUST_ROOT_ENV_KEYS);
});
});
});
it("blocks path-override vars (OPENCLAW_AGENT_DIR, OPENCLAW_BUNDLED_PLUGINS_DIR, PI_CODING_AGENT_DIR, OPENCLAW_OAUTH_DIR) from workspace .env", async () => {
await withIsolatedEnvAndCwd(async () => {
await withDotEnvFixture(async ({ base, cwdDir }) => {

View File

@@ -23,6 +23,7 @@ const BLOCKED_WORKSPACE_DOTENV_KEYS = new Set([
"CLAWHUB_TOKEN",
"CLAWHUB_URL",
"CLOUDSDK_PYTHON",
"COMSPEC",
"HTTP_PROXY",
"HTTPS_PROXY",
"HOMEBREW_BREW_FILE",