@joshuaswarren/openclaw-engram 9.0.21 → 9.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -25403,6 +25403,13 @@ function diffGraphSnapshots(previous, next) {
25403
25403
  }
25404
25404
 
25405
25405
  // src/dashboard-runtime.ts
25406
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1"]);
25407
+ function normalizeOriginHostname(hostname) {
25408
+ if (hostname.startsWith("[") && hostname.endsWith("]")) {
25409
+ return hostname.slice(1, -1);
25410
+ }
25411
+ return hostname;
25412
+ }
25406
25413
  function websocketAcceptKey(clientKey) {
25407
25414
  return createHash9("sha1").update(`${clientKey}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`).digest("base64");
25408
25415
  }
@@ -25572,11 +25579,17 @@ var GraphDashboardServer = class {
25572
25579
  handleUpgrade(req, socket) {
25573
25580
  const upgrade = typeof req.headers.upgrade === "string" ? req.headers.upgrade.toLowerCase() : "";
25574
25581
  const key = req.headers["sec-websocket-key"];
25582
+ const origin = typeof req.headers.origin === "string" ? req.headers.origin : "";
25575
25583
  if (upgrade !== "websocket" || typeof key !== "string") {
25576
25584
  socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
25577
25585
  socket.destroy();
25578
25586
  return;
25579
25587
  }
25588
+ if (!this.isAllowedOrigin(origin)) {
25589
+ socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
25590
+ socket.destroy();
25591
+ return;
25592
+ }
25580
25593
  const accept = websocketAcceptKey(key);
25581
25594
  socket.write(
25582
25595
  [
@@ -25602,6 +25615,19 @@ var GraphDashboardServer = class {
25602
25615
  });
25603
25616
  socket.write(encodeTextFrame(hello));
25604
25617
  }
25618
+ isAllowedOrigin(origin) {
25619
+ if (!origin) return false;
25620
+ try {
25621
+ const parsed = new URL(origin);
25622
+ const hostname = normalizeOriginHostname(parsed.hostname);
25623
+ if (!LOOPBACK_HOSTS.has(hostname)) return false;
25624
+ if (parsed.protocol !== "http:") return false;
25625
+ const originPort = parsed.port ? Number(parsed.port) : 80;
25626
+ return Number.isFinite(originPort) && originPort === this.boundPort;
25627
+ } catch {
25628
+ return false;
25629
+ }
25630
+ }
25605
25631
  broadcast(payload) {
25606
25632
  const frame = encodeTextFrame(JSON.stringify(payload));
25607
25633
  for (const [id, client] of this.clients.entries()) {