Fix harness forbidden error: use internal token instead of host check
The localhost check using host header and x-forwarded-for was unreliable in the standalone Next.js server which may inject forwarded headers internally. Replace with a per-process random token shared between the PTY server and the API route via env var.
This commit is contained in:
@@ -53,6 +53,7 @@ function attachPtyWebSocket(server) {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`http://127.0.0.1:${port}/api/agents/${encodeURIComponent(agentId)}/env`,
|
`http://127.0.0.1:${port}/api/agents/${encodeURIComponent(agentId)}/env`,
|
||||||
|
{ headers: { "x-internal-token": process.env.INTERNAL_API_TOKEN || "" } },
|
||||||
);
|
);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const body = await res.json().catch(() => ({}));
|
const body = await res.json().catch(() => ({}));
|
||||||
|
|||||||
@@ -2,11 +2,16 @@ const { createServer } = require("http");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { parse } = require("url");
|
const { parse } = require("url");
|
||||||
|
|
||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV !== "production";
|
const dev = process.env.NODE_ENV !== "production";
|
||||||
// HOSTNAME in K8s is the pod name — always bind to 0.0.0.0
|
// HOSTNAME in K8s is the pod name — always bind to 0.0.0.0
|
||||||
const hostname = "0.0.0.0";
|
const hostname = "0.0.0.0";
|
||||||
const port = parseInt(process.env.PORT || "3100", 10);
|
const port = parseInt(process.env.PORT || "3100", 10);
|
||||||
|
|
||||||
|
// Shared secret for internal PTY→API calls (generated per process)
|
||||||
|
process.env.INTERNAL_API_TOKEN = crypto.randomBytes(32).toString("hex");
|
||||||
|
|
||||||
// In production, load the standalone config to avoid webpack dependency
|
// In production, load the standalone config to avoid webpack dependency
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ export async function GET(
|
|||||||
_request: NextRequest,
|
_request: NextRequest,
|
||||||
{ params }: { params: Promise<{ id: string }> },
|
{ params }: { params: Promise<{ id: string }> },
|
||||||
) {
|
) {
|
||||||
// Only allow localhost access
|
// Only allow internal calls from the PTY server (same process)
|
||||||
const forwarded = _request.headers.get("x-forwarded-for");
|
const token = _request.headers.get("x-internal-token");
|
||||||
const host = _request.headers.get("host") ?? "";
|
if (!token || token !== process.env.INTERNAL_API_TOKEN) {
|
||||||
const isLocal =
|
|
||||||
!forwarded &&
|
|
||||||
(host.startsWith("localhost") || host.startsWith("127.0.0.1"));
|
|
||||||
if (!isLocal) {
|
|
||||||
return NextResponse.json({ error: "forbidden" }, { status: 403 });
|
return NextResponse.json({ error: "forbidden" }, { status: 403 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user