fix(agent-api): reject placeholder/weak AGENT_API_TOKEN as unconfigured
.env.example ships AGENT_API_TOKEN=replace-me, and unlike PB_SUPERUSER_PASSWORD's own replace-me placeholder, an unchanged agent token fails open: any caller sending "Bearer replace-me" would get full owner-equivalent access. Treat a secret that is unset, literally "replace-me", or shorter than 32 characters as not configured, matching the existing 500 behavior for an unset token. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
cf942d67c7
commit
8b55a10c02
2 changed files with 32 additions and 6 deletions
|
|
@ -20,7 +20,7 @@ describe("requireAgentToken", () => {
|
|||
});
|
||||
|
||||
it("refuses a request with no Authorization header", () => {
|
||||
process.env.AGENT_API_TOKEN = "secret123";
|
||||
process.env.AGENT_API_TOKEN = "secret123secret123secret123secret123";
|
||||
const request = new Request("http://localhost/api/agent/projects");
|
||||
|
||||
const result = requireAgentToken(request);
|
||||
|
|
@ -30,7 +30,7 @@ describe("requireAgentToken", () => {
|
|||
});
|
||||
|
||||
it("refuses a request with the wrong token", () => {
|
||||
process.env.AGENT_API_TOKEN = "secret123";
|
||||
process.env.AGENT_API_TOKEN = "secret123secret123secret123secret123";
|
||||
const request = new Request("http://localhost/api/agent/projects", {
|
||||
headers: { authorization: "Bearer wrong" },
|
||||
});
|
||||
|
|
@ -42,13 +42,37 @@ describe("requireAgentToken", () => {
|
|||
});
|
||||
|
||||
it("allows a request with the exact right token", () => {
|
||||
process.env.AGENT_API_TOKEN = "secret123";
|
||||
process.env.AGENT_API_TOKEN = "secret123secret123secret123secret123";
|
||||
const request = new Request("http://localhost/api/agent/projects", {
|
||||
headers: { authorization: "Bearer secret123" },
|
||||
headers: { authorization: "Bearer secret123secret123secret123secret123" },
|
||||
});
|
||||
|
||||
const result = requireAgentToken(request);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("refuses with 500 when the token is the literal placeholder, even with a matching header", () => {
|
||||
process.env.AGENT_API_TOKEN = "replace-me";
|
||||
const request = new Request("http://localhost/api/agent/projects", {
|
||||
headers: { authorization: "Bearer replace-me" },
|
||||
});
|
||||
|
||||
const result = requireAgentToken(request);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result!.status).toBe(500);
|
||||
});
|
||||
|
||||
it("refuses with 500 when the token is shorter than 32 characters, even with a matching header", () => {
|
||||
process.env.AGENT_API_TOKEN = "short";
|
||||
const request = new Request("http://localhost/api/agent/projects", {
|
||||
headers: { authorization: "Bearer short" },
|
||||
});
|
||||
|
||||
const result = requireAgentToken(request);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result!.status).toBe(500);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ import { jsonError } from "@/lib/http/json";
|
|||
*/
|
||||
export function requireAgentToken(request: Request): Response | null {
|
||||
const secret = process.env.AGENT_API_TOKEN;
|
||||
if (!secret) {
|
||||
console.error("[agent-api] AGENT_API_TOKEN is not set; refusing all requests");
|
||||
if (!secret || secret === "replace-me" || secret.length < 32) {
|
||||
console.error(
|
||||
"[agent-api] AGENT_API_TOKEN is not set to a real secret; refusing all requests"
|
||||
);
|
||||
return jsonError("Not configured", 500);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue