fix: silence unused hook token url param (#9436)

* fix: Gateway authentication token exposed in URL query parameters

* fix: silence unused hook token url param

* fix: remove gateway auth tokens from URLs (#9436) (thanks @coygeek)

* test: fix Windows path separators in audit test (#9436)

---------

Co-authored-by: George Pickett <gpickett00@gmail.com>
This commit is contained in:
Coy Geek
2026-02-05 18:08:29 -08:00
committed by GitHub
parent b1430aaaca
commit 717129f7f9
22 changed files with 107 additions and 172 deletions

View File

@@ -83,8 +83,8 @@ describe("dashboardCommand", () => {
customBindHost: undefined,
basePath: undefined,
});
expect(mocks.copyToClipboard).toHaveBeenCalledWith("http://127.0.0.1:18789/?token=abc123");
expect(mocks.openUrl).toHaveBeenCalledWith("http://127.0.0.1:18789/?token=abc123");
expect(mocks.copyToClipboard).toHaveBeenCalledWith("http://127.0.0.1:18789/");
expect(mocks.openUrl).toHaveBeenCalledWith("http://127.0.0.1:18789/");
expect(runtime.log).toHaveBeenCalledWith(
"Opened in your browser. Keep that tab to control OpenClaw.",
);

View File

@@ -23,7 +23,6 @@ export async function dashboardCommand(
const bind = cfg.gateway?.bind ?? "loopback";
const basePath = cfg.gateway?.controlUi?.basePath;
const customBindHost = cfg.gateway?.customBindHost;
const token = cfg.gateway?.auth?.token ?? process.env.OPENCLAW_GATEWAY_TOKEN ?? "";
const links = resolveControlUiLinks({
port,
@@ -31,11 +30,11 @@ export async function dashboardCommand(
customBindHost,
basePath,
});
const authedUrl = token ? `${links.httpUrl}?token=${encodeURIComponent(token)}` : links.httpUrl;
const dashboardUrl = links.httpUrl;
runtime.log(`Dashboard URL: ${authedUrl}`);
runtime.log(`Dashboard URL: ${dashboardUrl}`);
const copied = await copyToClipboard(authedUrl).catch(() => false);
const copied = await copyToClipboard(dashboardUrl).catch(() => false);
runtime.log(copied ? "Copied to clipboard." : "Copy to clipboard unavailable.");
let opened = false;
@@ -43,13 +42,12 @@ export async function dashboardCommand(
if (!options.noOpen) {
const browserSupport = await detectBrowserOpenSupport();
if (browserSupport.ok) {
opened = await openUrl(authedUrl);
opened = await openUrl(dashboardUrl);
}
if (!opened) {
hint = formatControlUiSshHint({
port,
basePath,
token: token || undefined,
});
}
} else {

View File

@@ -179,23 +179,16 @@ export async function detectBrowserOpenSupport(): Promise<BrowserOpenSupport> {
return { ok: true, command: resolved.command };
}
export function formatControlUiSshHint(params: {
port: number;
basePath?: string;
token?: string;
}): string {
export function formatControlUiSshHint(params: { port: number; basePath?: string }): string {
const basePath = normalizeControlUiBasePath(params.basePath);
const uiPath = basePath ? `${basePath}/` : "/";
const localUrl = `http://localhost:${params.port}${uiPath}`;
const tokenParam = params.token ? `?token=${encodeURIComponent(params.token)}` : "";
const authedUrl = params.token ? `${localUrl}${tokenParam}` : undefined;
const sshTarget = resolveSshTargetHint();
return [
"No GUI detected. Open from your computer:",
`ssh -N -L ${params.port}:127.0.0.1:${params.port} ${sshTarget}`,
"Then open:",
localUrl,
authedUrl,
"Docs:",
"https://docs.openclaw.ai/gateway/remote",
"https://docs.openclaw.ai/web/control-ui",