Gateway: add safer password-file input for gateway run#39067
Gateway: add safer password-file input for gateway run#39067vincentkoc merged 6 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR adds a Changes:
Issues found:
Confidence Score: 4/5
Last reviewed commit: 6713793 |
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🔵 Secret file reader lacks permission/symlink/size safeguards for --password-file
DescriptionThe new Impacts:
Vulnerable code: raw = fs.readFileSync(resolvedPath, "utf8");
const secret = raw.trim();While the CLI is local, this still matters in shared-host or managed-install scenarios where secret files may be provisioned with overly-permissive modes, or where the CLI could be executed with attacker-influenced paths. RecommendationHarden secret-file loading:
Example (POSIX-aware) approach: import fs from "node:fs";
const MAX_SECRET_BYTES = 64 * 1024;
export function readSecretFromFile(filePath: string, label: string): string {
const resolvedPath = resolveUserPath(filePath.trim());
if (!resolvedPath) throw new Error(`${label} file path is empty.`);
// Open first, then fstat to minimize TOCTOU.
const fd = fs.openSync(resolvedPath, fs.constants.O_RDONLY);
try {
const st = fs.fstatSync(fd);
if (!st.isFile()) throw new Error(`${label} file must be a regular file.`);
if (st.size > MAX_SECRET_BYTES) throw new Error(`${label} file is too large.`);
// POSIX permission/ownership checks (skip on platforms without getuid).
if (typeof process.getuid === "function") {
if ((st.mode & 0o077) !== 0) {
throw new Error(`${label} file permissions are too permissive (require 0600).`);
}
if (st.uid !== process.getuid()) {
throw new Error(`${label} file must be owned by the current user.`);
}
}
const buf = Buffer.allocUnsafe(Math.min(st.size, MAX_SECRET_BYTES));
const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
const raw = buf.subarray(0, bytesRead).toString("utf8").replace(/^\uFEFF/, "");
const secret = raw.trim();
if (!secret) throw new Error(`${label} file is empty.`);
return secret;
} finally {
fs.closeSync(fd);
}
}Analyzed PR: #39067 at commit Last updated on: 2026-03-08T02:25:21Z Latest run failed. Keeping previous successful results. Trace ID: Last updated on: 2026-03-08T02:25:37Z |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d56b80ca79
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 899cddc356
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (stat.isSymbolicLink()) { | ||
| throw new Error(`${label} file at ${resolvedPath} must not be a symlink.`); |
There was a problem hiding this comment.
Allow symlink-backed secret files
Hard-failing on stat.isSymbolicLink() breaks file-based auth in environments where mounted secrets are intentionally symlinked (for example, Kubernetes projected secrets where each key path points into ..data). Because readSecretFromFile is shared by gateway run and ACP secret-file flags, those flows now exit even though the secret payload is otherwise readable; this is a behavior regression from the previous implementation that accepted the path and read it.
Useful? React with 👍 / 👎.
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> (cherry picked from commit 4062aa5)
* CLI: add gateway password-file option * Docs: document safer gateway password input * Update src/cli/gateway-cli/run.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Tests: clean up gateway password temp dirs * CLI: restore gateway password warning flow * Security: harden secret file reads --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> (cherry picked from commit 4062aa5)
Summary
openclaw gateway run --password <secret>exposes the gateway password in local process listings.openclaw gateway run --password-file, warn on inline--password, and updated gateway CLI docs/changelog to prefer env or file-backed password input.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
openclaw gateway runnow accepts--password-file <path>.--passwordstill works, but now prints a warning that it can leak through process listings.OPENCLAW_GATEWAY_PASSWORD,--password-file, or SecretRef-backed config for password auth.Security Impact (required)
Yes/No): NoYes/No): YesYes/No): NoYes/No): NoYes/No): NoYes, explain risk + mitigation:Password input for
gateway runnow has a file-backed path and inline password usage emits a warning. This reduces accidental secret exposure in local process listings without changing gateway auth policy.Repro + Verification
Environment
Steps
openclaw gateway run --auth password --password-file /tmp/gateway-password.txt --allow-unconfigured.openclaw gateway run --auth password --password secret --allow-unconfiguredand verify the warning is printed.Expected
Actual
Evidence
Human Verification (required)
What you personally verified (not just CI), and how:
pnpm test src/cli/gateway-cli/run.option-collisions.test.ts--password-filehappy path, inline--passwordwarning,--password+--password-filecollision errorCompatibility / Migration
Yes/No): YesYes/No): NoYes/No): NoFailure Recovery (if this breaks)
--password-fileand fall back toOPENCLAW_GATEWAY_PASSWORDor prior inline--passwordbehaviorsrc/cli/gateway-cli/run.tsgateway runrejecting valid password-file input or failing to warn on inline--passwordRisks and Mitigations
src/cli/gateway-cli/run.option-collisions.test.ts.