fix: Unauthenticated Nostr profile API allows remote config tampering (#13719)

* fix(an-07): apply security fix

Generated by staged fix workflow.

* fix(an-07): apply security fix

Generated by staged fix workflow.

* fix(an-07): satisfy lint in plugin auth regression test

Replace unsafe unknown-to-string coercion in the gateway plugin auth test helper with explicit string/null/JSON handling so pnpm check passes.
This commit is contained in:
Coy Geek
2026-02-12 05:55:22 -08:00
committed by GitHub
parent acb9cbb898
commit 647d929c9d
3 changed files with 219 additions and 4 deletions

View File

@@ -333,6 +333,7 @@ export function createGatewayHttpServer(opts: {
try {
const configSnapshot = loadConfig();
const trustedProxies = configSnapshot.gateway?.trustedProxies ?? [];
const requestPath = new URL(req.url ?? "/", "http://localhost").pathname;
if (await handleHooksRequest(req, res)) {
return;
}
@@ -347,8 +348,26 @@ export function createGatewayHttpServer(opts: {
if (await handleSlackHttpRequest(req, res)) {
return;
}
if (handlePluginRequest && (await handlePluginRequest(req, res))) {
return;
if (handlePluginRequest) {
// Channel HTTP endpoints are gateway-auth protected by default.
// Non-channel plugin routes remain plugin-owned and must enforce
// their own auth when exposing sensitive functionality.
if (requestPath.startsWith("/api/channels/")) {
const token = getBearerToken(req);
const authResult = await authorizeGatewayConnect({
auth: resolvedAuth,
connectAuth: token ? { token, password: token } : null,
req,
trustedProxies,
});
if (!authResult.ok) {
sendUnauthorized(res);
return;
}
}
if (await handlePluginRequest(req, res)) {
return;
}
}
if (openResponsesEnabled) {
if (
@@ -372,8 +391,7 @@ export function createGatewayHttpServer(opts: {
}
}
if (canvasHost) {
const url = new URL(req.url ?? "/", "http://localhost");
if (isCanvasPath(url.pathname)) {
if (isCanvasPath(requestPath)) {
const ok = await authorizeCanvasRequest({
req,
auth: resolvedAuth,