ruflo 3.7.0-alpha.79 → 3.7.0-alpha.80

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruflo",
3
- "version": "3.7.0-alpha.79",
3
+ "version": "3.7.0-alpha.80",
4
4
  "description": "Ruflo - Enterprise AI agent orchestration platform. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "bin/ruflo.js",
6
6
  "type": "module",
@@ -56,7 +56,19 @@
56
56
  "make-fetch-happen": ">=15.0.0",
57
57
  "express-rate-limit": ">=8.4.1",
58
58
  "protobufjs": ">=7.5.5",
59
- "uuid": ">=14.0.0"
59
+ "uuid": ">=14.0.0",
60
+ "@opentelemetry/core": "1.25.1",
61
+ "@opentelemetry/resources": "1.25.1",
62
+ "@opentelemetry/sdk-trace-base": "1.25.1",
63
+ "@opentelemetry/sdk-node": ">=0.218.0",
64
+ "@opentelemetry/auto-instrumentations-node": ">=0.75.0",
65
+ "@opentelemetry/exporter-prometheus": ">=0.217.0",
66
+ "@opentelemetry/exporter-trace-otlp-grpc": "0.52.1",
67
+ "@opentelemetry/exporter-trace-otlp-http": "0.52.1",
68
+ "@opentelemetry/exporter-trace-otlp-proto": "0.52.1",
69
+ "@opentelemetry/otlp-exporter-base": "0.52.1",
70
+ "@opentelemetry/otlp-grpc-exporter-base": "0.52.1",
71
+ "@opentelemetry/otlp-transformer": "0.52.1"
60
72
  },
61
73
  "engines": {
62
74
  "node": ">=20.0.0"
@@ -639,11 +639,35 @@ Requires: OPENAI_API_KEY environment variable (already set for OpenAI models).
639
639
  return { guidance: `Unknown topic '${topic}'. Use 'overview', 'groups', or a specific group name.`, topic };
640
640
  }
641
641
 
642
+ // =============================================================================
643
+ // SSRF GUARD — Reject requests to private/loopback ranges (CWE-918)
644
+ // =============================================================================
645
+
646
+ const PRIVATE_IP_RE = /^(?:10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|127\.|0\.|::1|fc|fd)/i;
647
+
648
+ function assertSafeUrl(rawUrl) {
649
+ let parsed;
650
+ try {
651
+ parsed = new URL(rawUrl);
652
+ } catch {
653
+ throw new Error(`SSRF guard: invalid URL — ${rawUrl}`);
654
+ }
655
+ if (parsed.protocol !== "https:") {
656
+ throw new Error(`SSRF guard: only HTTPS URLs are permitted, got ${parsed.protocol}`);
657
+ }
658
+ const host = parsed.hostname;
659
+ if (PRIVATE_IP_RE.test(host) || host === "localhost" || host.endsWith(".local")) {
660
+ throw new Error(`SSRF guard: private/loopback host rejected — ${host}`);
661
+ }
662
+ }
663
+
642
664
  // =============================================================================
643
665
  // HELPER — Call a backend Cloud Function / API
644
666
  // =============================================================================
645
667
 
646
668
  async function callCloudFunction(url, payload, timeoutMs = 25000) {
669
+ // Validate the URL before making any network request.
670
+ assertSafeUrl(url);
647
671
  const controller = new AbortController();
648
672
  const timer = setTimeout(() => controller.abort(), timeoutMs);
649
673
  try {
@@ -728,11 +728,35 @@ async function geminiGroundedSearch(query, mode = "search") {
728
728
  }
729
729
  }
730
730
 
731
+ // =============================================================================
732
+ // SSRF GUARD — Reject requests to private/loopback ranges (CWE-918)
733
+ // =============================================================================
734
+
735
+ const PRIVATE_IP_RE = /^(?:10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|127\.|0\.|::1|fc|fd)/i;
736
+
737
+ function assertSafeUrl(rawUrl) {
738
+ let parsed;
739
+ try {
740
+ parsed = new URL(rawUrl);
741
+ } catch {
742
+ throw new Error(`SSRF guard: invalid URL — ${rawUrl}`);
743
+ }
744
+ if (parsed.protocol !== "https:") {
745
+ throw new Error(`SSRF guard: only HTTPS URLs are permitted, got ${parsed.protocol}`);
746
+ }
747
+ const host = parsed.hostname;
748
+ if (PRIVATE_IP_RE.test(host) || host === "localhost" || host.endsWith(".local")) {
749
+ throw new Error(`SSRF guard: private/loopback host rejected — ${host}`);
750
+ }
751
+ }
752
+
731
753
  // =============================================================================
732
754
  // HELPER — Call a backend Cloud Function / API
733
755
  // =============================================================================
734
756
 
735
757
  async function callCloudFunction(url, payload, timeoutMs = 25000) {
758
+ // Validate the URL before making any network request.
759
+ assertSafeUrl(url);
736
760
  const controller = new AbortController();
737
761
  const timer = setTimeout(() => controller.abort(), timeoutMs);
738
762
  try {