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

@@ -10,7 +10,9 @@ import { ConfigService } from "@nestjs/config";
import { firstValueFrom } from "rxjs";
import { PrismaService } from "../prisma/prisma.service";
import { CommandService } from "./command.service";
import { FederationAuditService } from "./audit.service";
import { FederationConnectionStatus } from "@prisma/client";
import { validateUrl } from "./utils/url-validator";
import type { CommandMessageDetails } from "./types/message.types";
import type {
SpawnAgentCommandPayload,
@@ -46,10 +48,24 @@ export class FederationAgentService {
private readonly prisma: PrismaService,
private readonly commandService: CommandService,
private readonly httpService: HttpService,
private readonly configService: ConfigService
private readonly configService: ConfigService,
private readonly auditService: FederationAuditService
) {
this.orchestratorUrl =
this.configService.get<string>("orchestrator.url") ?? "http://localhost:3001";
const url = this.configService.get<string>("orchestrator.url") ?? "";
const nodeEnv = this.configService.get<string>("NODE_ENV") ?? "production";
const isDevelopment = nodeEnv === "development" || nodeEnv === "test";
// Validate orchestrator URL (SSRF prevention)
const validationResult = validateUrl(url, isDevelopment);
if (!validationResult.valid) {
const errorMessage = validationResult.error ?? "Unknown validation error";
this.logger.error(`Invalid orchestrator URL: ${errorMessage}`);
// Log security event
this.auditService.logInvalidOrchestratorUrl(url, errorMessage);
throw new Error(errorMessage);
}
this.orchestratorUrl = url;
this.logger.log(
`FederationAgentService initialized with orchestrator URL: ${this.orchestratorUrl}`
);