Merge c14cd23c503a51495a66be0ab9b0b6c3f4ecdca1 into 598f1826d8b2bc969aace2c6459824737667218c

This commit is contained in:
Michael 2026-03-21 03:15:10 +00:00 committed by GitHub
commit a7acea52c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 0 deletions

View File

@ -649,4 +649,46 @@ describe("trusted-proxy auth", () => {
expect(res.ok).toBe(true);
expect(res.user).toBe("nick@example.com");
});
it("allows local direct loopback connections to bypass trusted-proxy auth", async () => {
const res = await authorizeGatewayConnect({
auth: {
mode: "trusted-proxy",
allowTailscale: false,
trustedProxy: trustedProxyConfig,
},
connectAuth: null,
trustedProxies: ["10.0.0.1"],
req: {
socket: { remoteAddress: "127.0.0.1" },
headers: {
host: "127.0.0.1:18789",
},
} as never,
});
expect(res.ok).toBe(true);
expect(res.method).toBe("none");
});
it("does not bypass trusted-proxy auth for non-loopback connections", async () => {
const res = await authorizeGatewayConnect({
auth: {
mode: "trusted-proxy",
allowTailscale: false,
trustedProxy: trustedProxyConfig,
},
connectAuth: null,
trustedProxies: ["10.0.0.1"],
req: {
socket: { remoteAddress: "192.168.1.50" },
headers: {
host: "192.168.1.50:18789",
},
} as never,
});
expect(res.ok).toBe(false);
expect(res.reason).toBe("trusted_proxy_untrusted_source");
});
});

View File

@ -380,6 +380,15 @@ export async function authorizeGatewayConnect(
);
if (auth.mode === "trusted-proxy") {
// Allow local direct connections (loopback, no proxy headers) to bypass
// trusted-proxy auth. Local CLI commands connect directly to 127.0.0.1
// without going through a reverse proxy, so they lack proxy identity
// headers. This is safe because only processes on the same machine can
// reach the loopback interface.
if (localDirect) {
return { ok: true, method: "none" };
}
if (!auth.trustedProxy) {
return { ok: false, reason: "trusted_proxy_config_missing" };
}