fix(#279): Validate orchestrator URL configuration (SSRF risk)
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

Implemented comprehensive URL validation to prevent SSRF attacks:
- Created URL validator utility with protocol whitelist (http/https only)
- Blocked access to private IP ranges (10.x, 192.168.x, 172.16-31.x)
- Blocked loopback addresses (127.x, localhost, 0.0.0.0)
- Blocked link-local addresses (169.254.x)
- Blocked IPv6 localhost (::1, ::)
- Allow localhost in development/test environments only
- Added structured audit logging for invalid URL attempts
- Comprehensive test coverage (37 tests for URL validator)

Security Impact:
- Prevents attackers from redirecting agent spawn requests to internal services
- Blocks data exfiltration via malicious orchestrator URL
- All agent operations now validated against SSRF

Files changed:
- apps/api/src/federation/utils/url-validator.ts (new)
- apps/api/src/federation/utils/url-validator.spec.ts (new)
- apps/api/src/federation/federation-agent.service.ts (validation integration)
- apps/api/src/federation/federation-agent.service.spec.ts (test updates)
- apps/api/src/federation/audit.service.ts (audit logging)
- apps/api/src/federation/federation.module.ts (service exports)

Fixes #279

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 20:47:41 -06:00
parent 09bb6df0b6
commit 0a527d2a4e
7 changed files with 489 additions and 4 deletions

View File

@@ -8,6 +8,7 @@ import { HttpService } from "@nestjs/axios";
import { ConfigService } from "@nestjs/config";
import { FederationAgentService } from "./federation-agent.service";
import { CommandService } from "./command.service";
import { FederationAuditService } from "./audit.service";
import { PrismaService } from "../prisma/prisma.service";
import { FederationConnectionStatus } from "@prisma/client";
import { of, throwError } from "rxjs";
@@ -55,10 +56,17 @@ describe("FederationAgentService", () => {
if (key === "orchestrator.url") {
return mockOrchestratorUrl;
}
if (key === "NODE_ENV") {
return "test";
}
return undefined;
}),
};
const mockAuditService = {
logInvalidOrchestratorUrl: vi.fn(),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
FederationAgentService,
@@ -66,6 +74,7 @@ describe("FederationAgentService", () => {
{ provide: PrismaService, useValue: mockPrisma },
{ provide: HttpService, useValue: mockHttpService },
{ provide: ConfigService, useValue: mockConfigService },
{ provide: FederationAuditService, useValue: mockAuditService },
],
}).compile();