Files
stack/apps/api/src/federation/audit.service.ts
T
jason.woltjeandClaude Sonnet 4.5 0a527d2a4e fix(#279): Validate orchestrator URL configuration (SSRF risk)
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 <[email protected]>
2026-02-03 20:47:41 -06:00

225 lines
5.8 KiB
TypeScript

/**
* Federation Audit Service
*
* Logs security-sensitive operations for compliance and monitoring.
* Uses application logger since ActivityLog requires workspace context.
*/
import { Injectable, Logger } from "@nestjs/common";
@Injectable()
export class FederationAuditService {
private readonly logger = new Logger(FederationAuditService.name);
/**
* Log instance keypair regeneration (system-level operation)
* Logged to application logs for security audit trail
*/
logKeypairRegeneration(userId: string, instanceId: string): void {
this.logger.warn({
event: "FEDERATION_KEYPAIR_REGENERATED",
userId,
instanceId,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log instance configuration update (system-level operation)
* Logged to application logs for security audit trail
*/
logInstanceConfigurationUpdate(
userId: string,
instanceId: string,
updates: Record<string, unknown>
): void {
this.logger.log({
event: "FEDERATION_INSTANCE_CONFIG_UPDATED",
userId,
instanceId,
updates,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log federated authentication initiation
*/
logFederatedAuthInitiation(userId: string, remoteInstanceId: string): void {
this.logger.log({
event: "FEDERATION_AUTH_INITIATED",
userId,
remoteInstanceId,
timestamp: new Date().toISOString(),
});
}
/**
* Log federated identity linking
*/
logFederatedIdentityLinked(userId: string, remoteInstanceId: string): void {
this.logger.log({
event: "FEDERATION_IDENTITY_LINKED",
userId,
remoteInstanceId,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log federated identity revocation
*/
logFederatedIdentityRevoked(userId: string, remoteInstanceId: string): void {
this.logger.warn({
event: "FEDERATION_IDENTITY_REVOKED",
userId,
remoteInstanceId,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log identity verification attempt
*/
logIdentityVerification(userId: string, remoteInstanceId: string, success: boolean): void {
const level = success ? "log" : "warn";
this.logger[level]({
event: "FEDERATION_IDENTITY_VERIFIED",
userId,
remoteInstanceId,
success,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log identity linking (create mapping)
*/
logIdentityLinking(localUserId: string, remoteInstanceId: string, remoteUserId: string): void {
this.logger.log({
event: "FEDERATION_IDENTITY_LINKED",
localUserId,
remoteUserId,
remoteInstanceId,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log identity revocation (remove mapping)
*/
logIdentityRevocation(localUserId: string, remoteInstanceId: string): void {
this.logger.warn({
event: "FEDERATION_IDENTITY_REVOKED",
localUserId,
remoteInstanceId,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log capability denial (security event)
* Logged when remote instance attempts operation without required capability
*/
logCapabilityDenied(
remoteInstanceId: string,
requiredCapability: string,
requestedUrl: string
): void {
this.logger.warn({
event: "FEDERATION_CAPABILITY_DENIED",
remoteInstanceId,
requiredCapability,
requestedUrl,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log incoming connection attempt
* Logged for all incoming connection requests (security monitoring)
*/
logIncomingConnectionAttempt(data: {
workspaceId: string;
remoteInstanceId: string;
remoteUrl: string;
timestamp: number;
}): void {
this.logger.log({
event: "FEDERATION_INCOMING_CONNECTION_ATTEMPT",
workspaceId: data.workspaceId,
remoteInstanceId: data.remoteInstanceId,
remoteUrl: data.remoteUrl,
requestTimestamp: new Date(data.timestamp).toISOString(),
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log incoming connection created
* Logged when an incoming connection is successfully created
*/
logIncomingConnectionCreated(data: {
workspaceId: string;
connectionId: string;
remoteInstanceId: string;
remoteUrl: string;
}): void {
this.logger.log({
event: "FEDERATION_INCOMING_CONNECTION_CREATED",
workspaceId: data.workspaceId,
connectionId: data.connectionId,
remoteInstanceId: data.remoteInstanceId,
remoteUrl: data.remoteUrl,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log incoming connection rejected
* Logged when an incoming connection is rejected (security event)
*/
logIncomingConnectionRejected(data: {
workspaceId: string;
remoteInstanceId: string;
remoteUrl?: string;
reason: string;
error?: string;
}): void {
this.logger.warn({
event: "FEDERATION_INCOMING_CONNECTION_REJECTED",
workspaceId: data.workspaceId,
remoteInstanceId: data.remoteInstanceId,
remoteUrl: data.remoteUrl,
reason: data.reason,
error: data.error,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
/**
* Log invalid orchestrator URL configuration attempt
* Logged when orchestrator URL validation fails (SSRF prevention)
*/
logInvalidOrchestratorUrl(url: string, error: string): void {
this.logger.warn({
event: "FEDERATION_INVALID_ORCHESTRATOR_URL",
url,
error,
timestamp: new Date().toISOString(),
securityEvent: true,
});
}
}