Skip to content

Security

Best practices for secure AgentForge deployments.

API Key Management

Never Commit Keys

typescript
// ❌ Never do this
const provider = new OpenAIProvider({
  apiKey: 'sk-1234567890abcdef',
});

// ✅ Use environment variables
const provider = new OpenAIProvider({
  apiKey: process.env.OPENAI_API_KEY,
});

Secret Managers

For production, use a secret manager:

typescript
// AWS Secrets Manager
import { SecretsManager } from '@aws-sdk/client-secrets-manager';

const secrets = new SecretsManager();
const { SecretString } = await secrets.getSecretValue({
  SecretId: 'agentforge/openai',
});

const provider = new OpenAIProvider({
  apiKey: JSON.parse(SecretString).apiKey,
});

Key Rotation

Rotate API keys regularly and implement graceful rotation:

typescript
class RotatingProvider {
  private provider: OpenAIProvider;
  
  async refresh() {
    const newKey = await fetchLatestKey();
    this.provider = new OpenAIProvider({ apiKey: newKey });
  }
}

Tool Execution Security

Input Validation

Always validate tool inputs with strict Zod schemas:

typescript
// ❌ Too permissive
const tool = defineTool({
  name: 'fetch',
  schema: z.object({ url: z.string() }), // Accepts any string
  execute: async ({ url }) => fetch(url),
});

// ✅ Strict validation
const tool = defineTool({
  name: 'fetch',
  schema: z.object({
    url: z.string()
      .url()
      .refine(
        (url) => ALLOWED_DOMAINS.some(d => url.includes(d)),
        'Domain not in allowlist'
      ),
  }),
  execute: async ({ url }) => fetch(url),
});

SSRF Prevention

Server-Side Request Forgery is a critical risk when tools fetch URLs:

typescript
const ALLOWED_DOMAINS = [
  'api.example.com',
  'data.example.com',
];

const BLOCKED_PATTERNS = [
  /^https?:\/\/localhost/,
  /^https?:\/\/127\./,
  /^https?:\/\/10\./,
  /^https?:\/\/192\.168\./,
  /^https?:\/\/172\.(1[6-9]|2[0-9]|3[0-1])\./,
];

function validateUrl(url: string): boolean {
  // Block internal networks
  if (BLOCKED_PATTERNS.some(p => p.test(url))) {
    return false;
  }
  
  // Only allow specific domains
  const parsed = new URL(url);
  return ALLOWED_DOMAINS.includes(parsed.hostname);
}

const safeFetchTool = defineTool({
  name: 'safe_fetch',
  schema: z.object({
    url: z.string().url().refine(validateUrl, 'URL not allowed'),
  }),
  execute: async ({ url }) => {
    // Additional runtime check
    if (!validateUrl(url)) {
      throw new Error('URL validation failed');
    }
    return fetch(url);
  },
});

Command Injection

If tools execute system commands:

typescript
// ❌ Dangerous - allows injection
const tool = defineTool({
  name: 'search_files',
  schema: z.object({ pattern: z.string() }),
  execute: async ({ pattern }) => {
    return exec(`grep -r "${pattern}" /data`); // Injection risk!
  },
});

// ✅ Safe - use parameterized execution
import { execFile } from 'child_process';

const tool = defineTool({
  name: 'search_files',
  schema: z.object({
    pattern: z.string().max(100).regex(/^[\w\s-]+$/),
  }),
  execute: async ({ pattern }) => {
    return new Promise((resolve, reject) => {
      execFile('grep', ['-r', pattern, '/data'], (err, stdout) => {
        if (err) reject(err);
        else resolve(stdout);
      });
    });
  },
});

Data Protection

Logging Redaction

Never log sensitive data:

typescript
import { LoggingMiddleware } from 'agentforge';

const logging = new LoggingMiddleware({
  logger: console,
  redactKeys: [
    'apiKey',
    'authorization',
    'password',
    'ssn',
    'creditCard',
    'token',
  ],
  redactPatterns: [
    /\b\d{3}-\d{2}-\d{4}\b/g,  // SSN
    /\b\d{16}\b/g,              // Credit card
    /Bearer\s+[\w-]+/g,         // Bearer tokens
  ],
});

PII in Conversations

Be cautious with conversation history:

typescript
// Implement PII detection before storing
function containsPII(text: string): boolean {
  const patterns = [
    /\b\d{3}-\d{2}-\d{4}\b/,      // SSN
    /\b\d{16}\b/,                  // Credit card
    /\b[\w.]+@[\w.]+\.\w+\b/,      // Email
  ];
  return patterns.some(p => p.test(text));
}

agent.on('message:add', ({ message }) => {
  if (containsPII(message.content)) {
    logger.warn('PII detected in conversation');
    // Optionally redact or reject
  }
});

Encryption at Rest

Encrypt stored conversations:

typescript
import { createCipheriv, createDecipheriv } from 'crypto';

class EncryptedMemory {
  private key: Buffer;
  
  encrypt(data: string): string {
    const iv = crypto.randomBytes(16);
    const cipher = createCipheriv('aes-256-gcm', this.key, iv);
    const encrypted = Buffer.concat([
      cipher.update(data, 'utf8'),
      cipher.final(),
    ]);
    const tag = cipher.getAuthTag();
    return Buffer.concat([iv, tag, encrypted]).toString('base64');
  }
  
  decrypt(data: string): string {
    const buffer = Buffer.from(data, 'base64');
    const iv = buffer.subarray(0, 16);
    const tag = buffer.subarray(16, 32);
    const encrypted = buffer.subarray(32);
    const decipher = createDecipheriv('aes-256-gcm', this.key, iv);
    decipher.setAuthTag(tag);
    return decipher.update(encrypted) + decipher.final('utf8');
  }
}

Rate Limiting

Protect against abuse:

typescript
import { RateLimiter } from 'agentforge';

const limiter = new RateLimiter({
  maxRequests: 100,
  windowMs: 60000, // 1 minute
  keyGenerator: (context) => context.userId,
  onLimit: (key) => {
    logger.warn('Rate limit exceeded', { userId: key });
  },
});

const agent = new Agent({
  provider,
  middleware: [limiter],
});

Audit Logging

Track all agent actions:

typescript
agent.on('request:complete', ({ requestId, input, output, userId }) => {
  auditLog.write({
    timestamp: new Date().toISOString(),
    requestId,
    userId,
    action: 'agent_request',
    inputHash: hash(input),  // Don't log full input
    toolsCalled: output.toolCalls?.map(t => t.name),
    success: true,
  });
});

agent.on('tool:execute', ({ tool, args, result, userId }) => {
  auditLog.write({
    timestamp: new Date().toISOString(),
    userId,
    action: 'tool_execution',
    tool: tool.name,
    argsHash: hash(args),
    success: !result.error,
  });
});

Security Checklist

Before deploying to production:

  • [ ] API keys stored in secret manager
  • [ ] Environment variables for all secrets
  • [ ] Tool inputs validated with strict Zod schemas
  • [ ] URL allowlists for fetch-based tools
  • [ ] SSRF patterns blocked
  • [ ] Sensitive data redacted from logs
  • [ ] PII detection implemented
  • [ ] Rate limiting configured
  • [ ] Audit logging enabled
  • [ ] Encryption for stored conversations
  • [ ] Regular key rotation scheduled

---

**File paths:**

docs/guide/architecture.md docs/guide/choosing-providers.md docs/guide/error-handling.md docs/guide/security.md

Released under the MIT License.