Skip to main content
Glama
security.ts4.84 kB
/** * Security utilities for input validation and sanitization. */ /** Maximum prompt length to prevent abuse */ export const MAX_PROMPT_LENGTH = 4000; /** Minimum prompt length for meaningful generation */ export const MIN_PROMPT_LENGTH = 3; /** Patterns that might indicate prompt injection attempts */ const SUSPICIOUS_PATTERNS = [ /ignore\s+(previous|all|above)(\s+\w+)*\s+instructions/i, /ignore\s+.*\s*instructions/i, /system\s*:\s*/i, /\[\[.*\]\]/, /<script/i, /javascript:/i, ]; export interface ValidationResult { valid: boolean; sanitized?: string; error?: string; } /** * Validate and sanitize a prompt for image generation. */ export function validatePrompt(prompt: string): ValidationResult { // Check for empty/missing if (!prompt || typeof prompt !== "string") { return { valid: false, error: "Prompt is required" }; } const trimmed = prompt.trim(); // Check length if (trimmed.length < MIN_PROMPT_LENGTH) { return { valid: false, error: `Prompt must be at least ${MIN_PROMPT_LENGTH} characters` }; } if (trimmed.length > MAX_PROMPT_LENGTH) { return { valid: false, error: `Prompt must be less than ${MAX_PROMPT_LENGTH} characters` }; } // Check for suspicious patterns for (const pattern of SUSPICIOUS_PATTERNS) { if (pattern.test(trimmed)) { return { valid: false, error: "Prompt contains disallowed patterns" }; } } // Basic sanitization - remove control characters const sanitized = trimmed .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/gu, "") // Remove control chars except newlines/tabs .replace(/\r\n/g, "\n") // Normalize line endings .replace(/\r/g, "\n"); return { valid: true, sanitized }; } /** * Validate a file path for safety. * Restricts paths to: * - Current working directory and subdirectories * - User's home directory and subdirectories * - System temp directory * - Relative paths (resolved relative to cwd) */ export function validateOutputPath(path: string): ValidationResult { if (!path || typeof path !== "string") { return { valid: true }; // Optional parameter } const trimmed = path.trim(); // Block obvious path traversal if (trimmed.includes("..")) { return { valid: false, error: "Path traversal not allowed" }; } // Block null bytes and other control characters if (/[\x00-\x1f]/.test(trimmed)) { return { valid: false, error: "Path contains invalid characters" }; } // If it's a relative path, it's allowed (will be resolved relative to cwd) if (!trimmed.startsWith("/") && !/^[A-Z]:\\/i.test(trimmed)) { return { valid: true, sanitized: trimmed }; } // For absolute paths, restrict to safe locations const homeDir = process.env.HOME || process.env.USERPROFILE || ""; const cwd = process.cwd(); const tempDirs = ["/tmp", "/var/tmp", process.env.TMPDIR || ""].filter(Boolean); // Check if path is under allowed directories const isUnderHome = homeDir && trimmed.startsWith(homeDir); const isUnderCwd = trimmed.startsWith(cwd); const isUnderTemp = tempDirs.some((tmp) => trimmed.startsWith(tmp)); if (!isUnderHome && !isUnderCwd && !isUnderTemp) { return { valid: false, error: "Absolute paths must be under your home directory, current working directory, or temp directory", }; } // Block obvious system directories even if they happen to be under home const dangerousPaths = ["/etc", "/var/log", "/usr", "/bin", "/sbin", "/root", "/boot"]; for (const dangerous of dangerousPaths) { if (trimmed.startsWith(dangerous)) { return { valid: false, error: "Cannot write to system directories" }; } } // Block Windows system paths if (/^[A-Z]:\\(Windows|Program Files|System)/i.test(trimmed)) { return { valid: false, error: "Cannot write to system directories" }; } return { valid: true, sanitized: trimmed }; } /** * Create a safe error message that doesn't leak sensitive info. */ export function safeErrorMessage(error: unknown): string { if (error instanceof Error) { // Remove any potential API keys from error messages let message = error.message; message = message.replace(/key[=:]["']?[A-Za-z0-9_-]{20,}["']?/gi, "key=[REDACTED]"); message = message.replace(/AIza[A-Za-z0-9_-]{35}/g, "[REDACTED_KEY]"); return message; } return "An unknown error occurred"; } /** * Redact sensitive information from an object for logging. */ export function redactSensitive<T extends Record<string, unknown>>(obj: T): T { const result = { ...obj }; const sensitiveKeys = ["apiKey", "api_key", "key", "token", "secret", "password"]; for (const key of Object.keys(result)) { if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk))) { result[key as keyof T] = "[REDACTED]" as T[keyof T]; } } return result; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/12-days-of-shipmas-2025/day-1-image-generation-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server