PMCR-O Security Best Practices: Protecting Autonomous Agents
Autonomous AI agents represent a new attack surface. Unlike traditional applications, PMCR-O agents make decisions, execute code, and access external systemsβmaking security not optional, but foundational.
This guide covers production-ready security patterns for PMCR-O deployments, from authentication to input validation to secrets management.
β οΈ Security First: PMCR-O agents can execute arbitrary code, access databases, and make API calls. Every security control must be defense-in-depthβassume any single layer can fail.
1. Authentication & Authorization
gRPC Service Authentication
All PMCR-O agent services (Planner, Maker, Checker, Reflector) should require authentication. Use gRPC interceptors for consistent enforcement:
C#
// Add authentication to gRPC services
builder.Services.AddGrpc(options =>
{
options.Interceptors.Add<AuthenticationInterceptor>();
options.Interceptors.Add<AuthorizationInterceptor>();
});
// Authentication interceptor
public class AuthenticationInterceptor : Interceptor
{
private readonly ILogger<AuthenticationInterceptor> _logger;
public AuthenticationInterceptor(ILogger<AuthenticationInterceptor> logger)
{
_logger = logger;
}
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
// Extract token from metadata
var token = context.RequestHeaders.GetValue("authorization")?.Replace("Bearer ", "");
if (string.IsNullOrEmpty(token))
{
throw new RpcException(new Status(StatusCode.Unauthenticated, "Missing authentication token"));
}
// Validate token (use your auth provider)
var principal = await ValidateTokenAsync(token);
if (principal == null)
{
throw new RpcException(new Status(StatusCode.Unauthenticated, "Invalid token"));
}
// Add user to context
context.UserState["Principal"] = principal;
return await continuation(request, context);
}
private async Task<ClaimsPrincipal> ValidateTokenAsync(string token)
{
// Implement your token validation (JWT, API key, etc.)
// Example with JWT:
var handler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey))
};
try
{
var principal = handler.ValidateToken(token, validationParameters, out _);
return principal;
}
catch
{
return null;
}
}
}
Role-Based Authorization
Different agents should have different permission levels:
C#
// Authorization interceptor
public class AuthorizationInterceptor : Interceptor
{
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
var principal = context.UserState["Principal"] as ClaimsPrincipal;
if (principal == null)
{
throw new RpcException(new Status(StatusCode.Unauthenticated, "Not authenticated"));
}
// Check required role
var requiredRole = GetRequiredRole(context.Method);
if (!principal.IsInRole(requiredRole))
{
_logger.LogWarning(
"User {User} attempted to access {Method} without role {Role}",
principal.Identity?.Name,
context.Method,
requiredRole);
throw new RpcException(new Status(StatusCode.PermissionDenied,
$"Required role: {requiredRole}"));
}
return await continuation(request, context);
}
private string GetRequiredRole(string method)
{
// Map methods to roles
if (method.Contains("Planner")) return "pmcro:planner";
if (method.Contains("Maker")) return "pmcro:maker";
if (method.Contains("Checker")) return "pmcro:checker";
if (method.Contains("Reflector")) return "pmcro:reflector";
return "pmcro:user";
}
}
2. Input Validation & Sanitization
Validate Agent Requests
Never trust user input. Validate all intents before processing:
C#
public override async Task<AgentResponse> ExecuteTask(
AgentRequest request,
ServerCallContext context)
{
// β
Validate input
var validationResult = ValidateIntent(request.Intent);
if (!validationResult.IsValid)
{
_logger.LogWarning("Invalid intent rejected: {Intent}", request.Intent);
return new AgentResponse
{
Content = $"Invalid input: {validationResult.ErrorMessage}",
Success = false
};
}
// β
Sanitize input (remove potential injection attempts)
var sanitizedIntent = SanitizeInput(request.Intent);
// Process with sanitized input
// ...
}
private ValidationResult ValidateIntent(string intent)
{
if (string.IsNullOrWhiteSpace(intent))
{
return ValidationResult.Fail("Intent cannot be empty");
}
if (intent.Length > 10000) // Max length
{
return ValidationResult.Fail("Intent exceeds maximum length");
}
// Check for dangerous patterns
var dangerousPatterns = new[]
{
@"