mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 16:30:57 +00:00
fix(dotenv): block connector endpoint workspace overrides (#70240)
* fix(dotenv): block connector endpoint workspace overrides * docs(changelog): note dotenv endpoint blocklist * fix(dotenv): block Matrix per-account scoped homeserver overrides
This commit is contained in:
@@ -58,6 +58,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/restart: preserve one-shot continuation instructions across gateway restarts so agents can resume and reply back to the original chat after reboot. (#63406) Thanks @VACInc.
|
||||
- Gateway/restart: write restart sentinel files atomically so interrupted writes cannot leave a truncated sentinel behind. (#70225) Thanks @obviyus.
|
||||
- Pairing: remove stale pending requests for a device when that paired device is deleted, so an old repair approval cannot recreate the removed device from leftover state.
|
||||
- Security/dotenv: block workspace `.env` overrides for Matrix, Mattermost, IRC, and Synology endpoint settings so cloned workspaces cannot redirect bundled connector traffic through local endpoint config. (#70240) Thanks @drobison00.
|
||||
|
||||
## 2026.4.21
|
||||
|
||||
|
||||
@@ -624,6 +624,9 @@ describe("workspace .env blocklist completeness", () => {
|
||||
"OPENCLAW_ALLOW_INSECURE_PRIVATE_WS",
|
||||
"OPENCLAW_BROWSER_EXECUTABLE_PATH",
|
||||
"EXAMPLE_API_HOST",
|
||||
"IRC_HOST",
|
||||
"MATTERMOST_URL",
|
||||
"MATRIX_HOMESERVER",
|
||||
"MINIMAX_API_HOST",
|
||||
"BROWSER_EXECUTABLE_PATH",
|
||||
"PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH",
|
||||
@@ -643,6 +646,8 @@ describe("workspace .env blocklist completeness", () => {
|
||||
"OPENCLAW_NODE_EXEC_HOST",
|
||||
"OPENCLAW_NODE_EXEC_FALLBACK",
|
||||
"OPENCLAW_ALLOW_PROJECT_LOCAL_BIN",
|
||||
"SYNOLOGY_CHAT_INCOMING_URL",
|
||||
"SYNOLOGY_NAS_HOST",
|
||||
];
|
||||
|
||||
await writeEnvFile(
|
||||
@@ -684,6 +689,62 @@ describe("workspace .env blocklist completeness", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("blocks bundled connector endpoint vars from workspace .env", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ cwdDir }) => {
|
||||
await writeEnvFile(
|
||||
path.join(cwdDir, ".env"),
|
||||
[
|
||||
"MATRIX_HOMESERVER=https://evil-matrix.example.com",
|
||||
"MATTERMOST_URL=https://evil-mattermost.example.com",
|
||||
"IRC_HOST=evil-irc.example.com",
|
||||
"SYNOLOGY_CHAT_INCOMING_URL=https://evil-synology.example.com/incoming",
|
||||
"SYNOLOGY_NAS_HOST=evil-synology.example.com",
|
||||
"SAFE_PROVIDER_URL=https://allowed.example.com",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
delete process.env.MATRIX_HOMESERVER;
|
||||
delete process.env.MATTERMOST_URL;
|
||||
delete process.env.IRC_HOST;
|
||||
delete process.env.SYNOLOGY_CHAT_INCOMING_URL;
|
||||
delete process.env.SYNOLOGY_NAS_HOST;
|
||||
delete process.env.SAFE_PROVIDER_URL;
|
||||
|
||||
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
|
||||
|
||||
expect(process.env.MATRIX_HOMESERVER).toBeUndefined();
|
||||
expect(process.env.MATTERMOST_URL).toBeUndefined();
|
||||
expect(process.env.IRC_HOST).toBeUndefined();
|
||||
expect(process.env.SYNOLOGY_CHAT_INCOMING_URL).toBeUndefined();
|
||||
expect(process.env.SYNOLOGY_NAS_HOST).toBeUndefined();
|
||||
expect(process.env.SAFE_PROVIDER_URL).toBe("https://allowed.example.com");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("blocks Matrix per-account scoped homeserver vars from workspace .env", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ cwdDir }) => {
|
||||
await writeEnvFile(
|
||||
path.join(cwdDir, ".env"),
|
||||
[
|
||||
"MATRIX_DEFAULT_HOMESERVER=https://evil-default.example.com",
|
||||
"MATRIX_OPS_HOMESERVER=https://evil-ops.example.com",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
delete process.env.MATRIX_DEFAULT_HOMESERVER;
|
||||
delete process.env.MATRIX_OPS_HOMESERVER;
|
||||
|
||||
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
|
||||
|
||||
expect(process.env.MATRIX_DEFAULT_HOMESERVER).toBeUndefined();
|
||||
expect(process.env.MATRIX_OPS_HOMESERVER).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("blocks generic endpoint-routing suffixes from workspace .env", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ cwdDir }) => {
|
||||
|
||||
@@ -21,6 +21,9 @@ const BLOCKED_WORKSPACE_DOTENV_KEYS = new Set([
|
||||
"CLAWHUB_URL",
|
||||
"HTTP_PROXY",
|
||||
"HTTPS_PROXY",
|
||||
"IRC_HOST",
|
||||
"MATTERMOST_URL",
|
||||
"MATRIX_HOMESERVER",
|
||||
"MINIMAX_API_HOST",
|
||||
"NODE_TLS_REJECT_UNAUTHORIZED",
|
||||
"NO_PROXY",
|
||||
@@ -66,11 +69,15 @@ const BLOCKED_WORKSPACE_DOTENV_KEYS = new Set([
|
||||
"OPENCLAW_TEST_TAILSCALE_BINARY",
|
||||
"PI_CODING_AGENT_DIR",
|
||||
"PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH",
|
||||
"SYNOLOGY_CHAT_INCOMING_URL",
|
||||
"SYNOLOGY_NAS_HOST",
|
||||
"UV_PYTHON",
|
||||
]);
|
||||
|
||||
// Block endpoint redirection for any service without overfitting per-provider names.
|
||||
const BLOCKED_WORKSPACE_DOTENV_SUFFIXES = ["_API_HOST", "_BASE_URL"];
|
||||
// `_HOMESERVER` covers Matrix's per-account scoped keys (MATRIX_<ACCOUNT>_HOMESERVER)
|
||||
// in addition to the bare MATRIX_HOMESERVER listed above.
|
||||
const BLOCKED_WORKSPACE_DOTENV_SUFFIXES = ["_API_HOST", "_BASE_URL", "_HOMESERVER"];
|
||||
const BLOCKED_WORKSPACE_DOTENV_PREFIXES = [
|
||||
"ANTHROPIC_API_KEY_",
|
||||
"CLAWHUB_",
|
||||
|
||||
Reference in New Issue
Block a user