Security Best Practices
Writing secure automation scripts with Utah. Learn security patterns, vulnerability prevention, and best practices for building trustworthy automation systems.
Prerequisites
- Understanding of security fundamentals
 - Knowledge of common vulnerabilities
 - Experience with access control concepts
 - Familiarity with secure coding practices
 
Input Validation and Sanitization
Command Injection Prevention
script.description("Prevent command injection vulnerabilities");
// Unsafe: Direct command construction with user input
function unsafeCommandExecution(userInput: string): void {
  console.log("❌ UNSAFE: Direct command construction");
  // This is vulnerable to command injection
  // let result: string = "$(ls ${userInput})";
  console.log("This would be vulnerable if executed");
}
// Safe: Input validation and sanitization
function safeCommandExecution(userInput: string): void {
  console.log("✅ SAFE: Validated command execution");
  // Validate input format
  if (!isValidPath(userInput)) {
    console.log("❌ Invalid path format");
    exit(1);
  }
  // Sanitize input
  let sanitizedPath: string = sanitizePath(userInput);
  // Use validated input
  if (fs.exists(sanitizedPath)) {
    let result: string = "$(ls "${sanitizedPath}")";
    console.log("Directory contents: ${result.substring(0, 100)}...");
  } else {
    console.log("Directory does not exist");
  }
}
// Input validation functions
function isValidPath(path: string): boolean {
  // Check for dangerous characters
  let dangerousChars: string[] = [";", "&", "|", "`", "$", "(", ")", "<", ">"];
  for (let char: string in dangerousChars) {
    if (path.contains(char)) {
      console.log("❌ Dangerous character detected: ${char}");
      return false;
    }
  }
  // Check for directory traversal
  if (path.contains("..") || path.contains("./")) {
    console.log("❌ Directory traversal attempt detected");
    return false;
  }
  // Check path length
  if (path.length > 255) {
    console.log("❌ Path too long");
    return false;
  }
  // Check for absolute path outside allowed directories
  if (path.startsWith("/") && !isAllowedAbsolutePath(path)) {
    console.log("❌ Absolute path not allowed");
    return false;
  }
  return true;
}
function sanitizePath(path: string): string {
  // Remove any remaining dangerous characters
  let sanitized: string = path.replace(/[;&|`$()<>]/g, "");
  // Normalize path separators
  sanitized = sanitized.replace(/\/+/g, "/");
  // Remove leading/trailing whitespace
  sanitized = sanitized.trim();
  return sanitized;
}
function isAllowedAbsolutePath(path: string): boolean {
  let allowedPrefixes: string[] = ["/tmp/", "/var/tmp/", "/home/", "/opt/myapp/"];
  for (let prefix: string in allowedPrefixes) {
    if (path.startsWith(prefix)) {
      return true;
    }
  }
  return false;
}
// Example usage
let testInputs: string[] = [
  "/tmp/safe-directory",
  "relative/path",
  "../../etc/passwd",       // Directory traversal
  "/tmp/test; rm -rf /",    // Command injection
  "/etc/shadow",            // Unauthorized access
  "normal-file.txt"         // Safe input
];
for (let input: string in testInputs) {
  console.log("\nTesting input: ${input}");
  safeCommandExecution(input);
}
File Path Validation
script.description("Secure file path handling and validation");
// Secure file operations class
class SecureFileHandler {
  private allowedDirectories: string[];
  private maxFileSize: number; // bytes
  private allowedExtensions: string[];
  constructor(allowedDirs: string[], maxSize: number, allowedExts: string[]) {
    this.allowedDirectories = allowedDirs;
    this.maxFileSize = maxSize;
    this.allowedExtensions = allowedExts;
  }
  validateFilePath(filePath: string): boolean {
    // Resolve absolute path
    let absolutePath: string = fs.path(filePath);
    // Check if path is within allowed directories
    let isAllowed: boolean = false;
    for (let allowedDir: string in this.allowedDirectories) {
      if (absolutePath.startsWith(fs.path(allowedDir))) {
        isAllowed = true;
        break;
      }
    }
    if (!isAllowed) {
      console.log("❌ File path not in allowed directories: ${absolutePath}");
      return false;
    }
    // Check file extension
    let extension: string = fs.extension(filePath).toLowerCase();
    if (this.allowedExtensions.length > 0 && !this.allowedExtensions.contains(extension)) {
      console.log("❌ File extension not allowed: ${extension}");
      return false;
    }
    // Check if file exists and get size
    if (fs.exists(absolutePath)) {
      let fileSize: number = parseInt("$(stat -c%s "${absolutePath}" 2>/dev/null || echo "0")");
      if (fileSize > this.maxFileSize) {
        console.log("❌ File too large: ${fileSize} bytes (max: ${this.maxFileSize})");
        return false;
      }
    }
    return true;
  }
  secureReadFile(filePath: string): string | null {
    if (!this.validateFilePath(filePath)) {
      return null;
    }
    let absolutePath: string = fs.path(filePath);
    try {
      let content: string = fs.readFile(absolutePath);
      console.log("✅ Securely read file: ${absolutePath}");
      return content;
    } catch {
      console.log("❌ Error reading file: ${absolutePath}");
      return null;
    }
  }
  secureWriteFile(filePath: string, content: string): boolean {
    if (!this.validateFilePath(filePath)) {
      return false;
    }
    let absolutePath: string = fs.path(filePath);
    // Additional check for write operations
    if (content.length > this.maxFileSize) {
      console.log("❌ Content too large: ${content.length} bytes");
      return false;
    }
    // Create backup if file exists
    if (fs.exists(absolutePath)) {
      let backupPath: string = "${absolutePath}.backup.$(date +%s)";
      fs.copyFile(absolutePath, backupPath);
      console.log("📁 Created backup: ${backupPath}");
    }
    try {
      fs.writeFile(absolutePath, content);
      console.log("✅ Securely wrote file: ${absolutePath}");
      return true;
    } catch {
      console.log("❌ Error writing file: ${absolutePath}");
      return false;
    }
  }
}
// Example usage
let fileHandler: SecureFileHandler = new SecureFileHandler(
  ["/tmp", "/var/tmp", "/home/user/workspace"],  // Allowed directories
  1048576,  // 1MB max file size
  [".txt", ".json", ".yaml", ".log"]  // Allowed extensions
);
// Test secure file operations
let testFiles: string[] = [
  "/tmp/safe-file.txt",
  "/etc/passwd",              // Outside allowed dirs
  "/tmp/large-file.exe",      // Wrong extension
  "../../../etc/shadow",       // Directory traversal
  "/tmp/normal-file.json"     // Safe file
];
for (let testFile: string in testFiles) {
  console.log("\nTesting file: ${testFile}");
  // Test read operation
  let content: string | null = fileHandler.secureReadFile(testFile);
  if (content !== null) {
    // Test write operation
    let success: boolean = fileHandler.secureWriteFile(testFile, "Secure content");
    console.log("Write result: ${success ? "Success" : "Failed"}");
  }
}
Credential and Secret Management
Secure Credential Handling
script.description("Secure handling of credentials and secrets");
// Secure credential manager
class CredentialManager {
  private credentialFile: string;
  private encryptionKey: string;
  constructor(credFile: string) {
    this.credentialFile = credFile;
    this.encryptionKey = this.getEncryptionKey();
  }
  private getEncryptionKey(): string {
    // Try to get encryption key from environment
    let key: string = env.get("CREDENTIAL_ENCRYPTION_KEY") || "";
    if (key == "") {
      // Generate key from system information (not recommended for production)
      let hostname: string = `$(hostname)`;
      let user: string = `$(whoami)`;
      key = "${hostname}-${user}-default-key";
      console.log("⚠️  Using default encryption key. Set CREDENTIAL_ENCRYPTION_KEY environment variable.");
    }
    return key;
  }
  private encryptCredential(credential: string): string {
    // Simple XOR encryption (use proper encryption in production)
    let encrypted: string = "";
    let key: string = this.encryptionKey;
    for (let i: number = 0; i < credential.length; i++) {
      let charCode: number = credential.charCodeAt(i);
      let keyChar: number = key.charCodeAt(i % key.length);
      encrypted += String.fromCharCode(charCode ^ keyChar);
    }
    // Base64 encode the result
    return "$(echo -n "${encrypted}" | base64 -w 0)";
  }
  private decryptCredential(encryptedCredential: string): string {
    // Decode from base64
    let encrypted: string = "$(echo "${encryptedCredential}" | base64 -d)";
    // Simple XOR decryption
    let decrypted: string = "";
    let key: string = this.encryptionKey;
    for (let i: number = 0; i < encrypted.length; i++) {
      let charCode: number = encrypted.charCodeAt(i);
      let keyChar: number = key.charCodeAt(i % key.length);
      decrypted += String.fromCharCode(charCode ^ keyChar);
    }
    return decrypted;
  }
  storeCredential(name: string, credential: string): boolean {
    console.log("Storing credential: ${name}");
    let encrypted: string = this.encryptCredential(credential);
    let credentials: object = {};
    if (fs.exists(this.credentialFile)) {
      try {
        let content: string = fs.readFile(this.credentialFile);
        credentials = json.parse(content);
      } catch {
        console.log("⚠️  Could not read existing credentials file");
      }
    }
    credentials = json.set(credentials, ".${name}", {
      "encrypted_value": encrypted,
      "created_at": `$(date -Iseconds)`,
      "last_accessed": `$(date -Iseconds)`
    });
    // Set secure file permissions
    fs.writeFile(this.credentialFile, json.stringify(credentials, true));
    "$(chmod 600 "${this.credentialFile}")";
    console.log("✅ Credential stored securely: ${name}");
    return true;
  }
  getCredential(name: string): string | null {
    if (!fs.exists(this.credentialFile)) {
      console.log("❌ Credentials file not found");
      return null;
    }
    try {
      let content: string = fs.readFile(this.credentialFile);
      let credentials: object = json.parse(content);
      if (!json.has(credentials, ".${name}")) {
        console.log("❌ Credential not found: ${name}");
        return null;
      }
      let credData: object = json.get(credentials, ".${name}");
      let encrypted: string = json.getString(credData, ".encrypted_value");
      // Update last accessed time
      credData = json.set(credData, ".last_accessed", `$(date -Iseconds)`);
      credentials = json.set(credentials, ".${name}", credData);
      fs.writeFile(this.credentialFile, json.stringify(credentials, true));
      let decrypted: string = this.decryptCredential(encrypted);
      console.log("✅ Retrieved credential: ${name}");
      return decrypted;
    } catch {
      console.log("❌ Error retrieving credential: ${name}");
      return null;
    }
  }
  listCredentials(): string[] {
    if (!fs.exists(this.credentialFile)) {
      return [];
    }
    try {
      let content: string = fs.readFile(this.credentialFile);
      let credentials: object = json.parse(content);
      return json.keys(credentials);
    } catch {
      return [];
    }
  }
  deleteCredential(name: string): boolean {
    if (!fs.exists(this.credentialFile)) {
      console.log("❌ Credentials file not found");
      return false;
    }
    try {
      let content: string = fs.readFile(this.credentialFile);
      let credentials: object = json.parse(content);
      if (!json.has(credentials, ".${name}")) {
        console.log("❌ Credential not found: ${name}");
        return false;
      }
      credentials = json.delete(credentials, ".${name}");
      fs.writeFile(this.credentialFile, json.stringify(credentials, true));
      console.log("✅ Credential deleted: ${name}");
      return true;
    } catch {
      console.log("❌ Error deleting credential: ${name}");
      return false;
    }
  }
}
// Example usage
let credManager: CredentialManager = new CredentialManager("/tmp/secure_credentials.json");
// Store some test credentials
credManager.storeCredential("database_password", "super_secret_password");
credManager.storeCredential("api_key", "abc123def456ghi789");
credManager.storeCredential("ssh_passphrase", "my_ssh_key_passphrase");
// List stored credentials
let credNames: string[] = credManager.listCredentials();
console.log("Stored credentials: ${credNames.join(", ")}");
// Retrieve and use credentials
let dbPassword: string | null = credManager.getCredential("database_password");
if (dbPassword !== null) {
  console.log("Database password retrieved (length: ${dbPassword.length})");
  // Use password for database connection...
}
// Clean up test credentials
credManager.deleteCredential("database_password");
credManager.deleteCredential("api_key");
credManager.deleteCredential("ssh_passphrase");
Environment Variable Security
script.description("Secure environment variable handling");
// Secure environment variable manager
function secureEnvSetup(): void {
  console.log("Setting up secure environment...");
  // Check for sensitive data in environment
  let sensitivePatterns: string[] = [
    "password", "secret", "key", "token", "credential",
    "passwd", "pwd", "auth", "private"
  ];
  console.log("Scanning environment for potentially sensitive variables:");
  let envVars: string[] = `$(env | cut -d'=' -f1)`.split("\n");
  for (let varName: string in envVars) {
    if (varName.trim() != "") {
      let lowerName: string = varName.toLowerCase();
      for (let pattern: string in sensitivePatterns) {
        if (lowerName.contains(pattern)) {
          console.log("⚠️  Potentially sensitive environment variable: ${varName}");
          // Check if it's properly protected
          let value: string = env.get(varName) || "";
          if (value.length < 20) {
            console.log(`   Warning: Short value might not be secure`);
          }
          break;
        }
      }
    }
  }
}
// Function to mask sensitive output
function maskSensitiveOutput(output: string): string {
  let sensitivePatterns: string[] = [
    "password=\\S+",
    "secret=\\S+",
    "key=\\S+",
    "token=\\S+",
    "Bearer \\S+",
    "Basic \\S+"
  ];
  let masked: string = output;
  for (let pattern: string in sensitivePatterns) {
    // Replace sensitive data with asterisks
    masked = "$(echo "${masked}" | sed -E 's/${pattern}/[REDACTED]/g')";
  }
  return masked;
}
// Secure command execution with output masking
function secureCommandExecution(command: string, description: string): void {
  console.log("Executing: ${description}");
  let output: string = "$(${command} 2>&1)";
  let maskedOutput: string = maskSensitiveOutput(output);
  console.log("Output: ${maskedOutput}");
}
// Example usage
secureEnvSetup();
// Test output masking
let testCommands: string[] = [
  "echo 'password=secret123'",
  "echo 'API response: {\"token\": \"abc123\", \"data\": \"public\"}'",
  "echo 'Authorization: Bearer xyz789token'"
];
for (let cmd: string in testCommands) {
  secureCommandExecution(cmd, "Test command with sensitive data");
}
Access Control and Permissions
File Permission Management
script.description("Secure file permission management");
// Secure file permission class
class FilePermissionManager {
  // Set secure permissions for different file types
  setSecurePermissions(filePath: string, fileType: string): boolean {
    if (!fs.exists(filePath)) {
      console.log("❌ File not found: ${filePath}");
      return false;
    }
    let permissions: string = "";
    switch (fileType) {
      case "config":
        permissions = "640";  // Owner read/write, group read
        break;
      case "secret":
        permissions = "600";  // Owner read/write only
        break;
      case "script":
        permissions = "750";  // Owner read/write/execute, group read/execute
        break;
      case "public":
        permissions = "644";  // Owner read/write, group/other read
        break;
      case "private":
        permissions = "600";  // Owner read/write only
        break;
      default:
        console.log("❌ Unknown file type: ${fileType}");
        return false;
    }
    "$(chmod ${permissions} "${filePath}")";
    // Verify permissions were set correctly
    let actualPerms: string = "$(stat -c %a "${filePath}")";
    if (actualPerms == permissions) {
      console.log("✅ Set ${fileType} permissions ${permissions} on ${filePath}");
      return true;
    } else {
      console.log("❌ Failed to set permissions on ${filePath} (expected: ${permissions}, actual: ${actualPerms})");
      return false;
    }
  }
  // Audit file permissions
  auditPermissions(directory: string): object {
    console.log("Auditing permissions in: ${directory}");
    let audit: object = {
      "directory": directory,
      "timestamp": `$(date -Iseconds)`,
      "issues": [],
      "summary": {
        "total_files": 0,
        "secure_files": 0,
        "insecure_files": 0
      }
    };
    let files: string[] = "$(find "${directory}" -type f)".split("\n");
    for (let file: string in files) {
      if (file.trim() != "") {
        let perms: string = "$(stat -c %a "${file}")";
        let owner: string = "$(stat -c %U "${file}")";
        let group: string = "$(stat -c %G "${file}")";
        let totalFiles: number = json.getNumber(audit, ".summary.total_files") + 1;
        audit = json.set(audit, ".summary.total_files", totalFiles);
        // Check for insecure permissions
        let isInsecure: boolean = false;
        let issues: string[] = [];
        // Check for world-writable files
        if (perms.endsWith("2") || perms.endsWith("6") || perms.endsWith("7")) {
          isInsecure = true;
          issues.push("World-writable");
        }
        // Check for executable files with broad permissions
        if ((perms.endsWith("5") || perms.endsWith("7")) && perms.startsWith("7")) {
          if (perms == "755" || perms == "777") {
            isInsecure = true;
            issues.push("Broadly executable");
          }
        }
        // Check for config files with loose permissions
        if (file.contains("config") || file.contains(".conf") || file.contains(".cfg")) {
          if (perms != "600" && perms != "640" && perms != "644") {
            isInsecure = true;
            issues.push("Config file with loose permissions");
          }
        }
        if (isInsecure) {
          let auditIssues: object[] = json.get(audit, ".issues");
          auditIssues.push({
            "file": file,
            "permissions": perms,
            "owner": owner,
            "group": group,
            "issues": issues
          });
          audit = json.set(audit, ".issues", auditIssues);
          let insecureCount: number = json.getNumber(audit, ".summary.insecure_files") + 1;
          audit = json.set(audit, ".summary.insecure_files", insecureCount);
        } else {
          let secureCount: number = json.getNumber(audit, ".summary.secure_files") + 1;
          audit = json.set(audit, ".summary.secure_files", secureCount);
        }
      }
    }
    return audit;
  }
  // Fix common permission issues
  fixPermissionIssues(auditResults: object): void {
    console.log("Fixing permission issues...");
    let issues: object[] = json.get(auditResults, ".issues");
    for (let issue: object in issues) {
      let file: string = json.getString(issue, ".file");
      let currentPerms: string = json.getString(issue, ".permissions");
      let problemList: string[] = json.get(issue, ".issues");
      console.log("Fixing ${file} (current: ${currentPerms})");
      for (let problem: string in problemList) {
        if (problem == "World-writable") {
          // Remove world write permission
          "$(chmod o-w "${file}")";
          console.log(`  ✅ Removed world write permission`);
        } else if (problem == "Broadly executable") {
          // Set safer permissions for executables
          "$(chmod 750 "${file}")";
          console.log(`  ✅ Set safer executable permissions (750)`);
        } else if (problem.contains("Config file")) {
          // Set secure config permissions
          "$(chmod 640 "${file}")";
          console.log(`  ✅ Set secure config permissions (640)`);
        }
      }
    }
  }
}
// Example usage
let permManager: FilePermissionManager = new FilePermissionManager();
// Create test files with various permissions
let testDir: string = "/tmp/permission_test";
fs.createDirectory(testDir);
let testFiles: object = {
  "config.txt": "config",
  "secret.key": "secret",
  "script.sh": "script",
  "public.txt": "public",
  "private.data": "private"
};
let fileNames: string[] = json.keys(testFiles);
for (let fileName: string in fileNames) {
  let filePath: string = "${testDir}/${fileName}";
  let fileType: string = json.getString(testFiles, ".${fileName}");
  // Create test file
  fs.writeFile(filePath, "Test content for ${fileName}");
  // Set secure permissions
  permManager.setSecurePermissions(filePath, fileType);
}
// Audit permissions
let auditResults: object = permManager.auditPermissions(testDir);
console.log("\nPermission audit results:");
console.log(json.stringify(auditResults, true));
// Clean up
"$(rm -rf ${testDir})";
User and Process Security
script.description("User and process security management");
// Security context checker
function checkSecurityContext(): object {
  console.log("Checking security context...");
  let context: object = {
    "timestamp": `$(date -Iseconds)`,
    "user": {
      "current_user": `$(whoami)`,
      "effective_uid": parseInt(`$(id -u)`),
      "effective_gid": parseInt(`$(id -g)`),
      "groups": `$(groups)`.split(" "),
      "is_root": parseInt(`$(id -u)`) == 0
    },
    "process": {
      "pid": parseInt(`$$`),
      "ppid": parseInt(`$(ps -o ppid= -p $$)`),
      "session_id": `$(ps -o sid= -p $$)`.trim()
    },
    "security_checks": {}
  };
  // Check if running as root
  let isRoot: boolean = json.getBoolean(context, ".user.is_root");
  if (isRoot) {
    console.log("⚠️  Running as root - elevated privileges detected");
    context = json.set(context, ".security_checks.root_warning", true);
  } else {
    console.log("✅ Running as non-root user");
    context = json.set(context, ".security_checks.root_warning", false);
  }
  // Check for sudo usage
  let sudoUser: string = env.get("SUDO_USER") || "";
  if (sudoUser != "") {
    console.log("⚠️  Script executed via sudo by user: ${sudoUser}");
    context = json.set(context, ".security_checks.sudo_usage", true);
    context = json.set(context, ".security_checks.original_user", sudoUser);
  } else {
    context = json.set(context, ".security_checks.sudo_usage", false);
  }
  // Check umask
  let umask: string = `$(umask)`;
  context = json.set(context, ".security_checks.umask", umask);
  if (umask != "0022" && umask != "0077") {
    console.log("⚠️  Unusual umask detected: ${umask}");
    context = json.set(context, ".security_checks.unusual_umask", true);
  } else {
    context = json.set(context, ".security_checks.unusual_umask", false);
  }
  return context;
}
// Privilege escalation detection
function detectPrivilegeEscalation(): void {
  console.log("Checking for privilege escalation attempts...");
  // Check for SUID/SGID files in common locations
  let suspiciousPaths: string[] = ["/tmp", "/var/tmp", "/dev/shm"];
  for (let path: string in suspiciousPaths) {
    if (fs.exists(path)) {
      let suidFiles: string[] = "$(find "${path}" -type f \\( -perm -4000 -o -perm -2000 \\) 2>/dev/null)".split("\n");
      for (let file: string in suidFiles) {
        if (file.trim() != "") {
          console.log("⚠️  SUID/SGID file found in ${path}: ${file}");
        }
      }
    }
  }
  // Check for unusual process ownership
  let processes: string[] = `$(ps -eo user,pid,ppid,command --no-headers)`.split("\n");
  for (let process: string in processes) {
    if (process.trim() != "") {
      let fields: string[] = process.trim().split(/\s+/);
      if (fields.length >= 4) {
        let user: string = fields[0];
        let pid: string = fields[1];
        let command: string = fields.slice(3).join(" ");
        // Check for processes running as different users
        if (user == "root" && command.contains("sudo")) {
          console.log("ℹ️  Root process via sudo: ${command.substring(0, 50)}...");
        }
      }
    }
  }
}
// Secure process execution
function executeSecurely(command: string, dropPrivileges: boolean = true): string {
  console.log("Executing securely: ${command.substring(0, 50)}...");
  if (dropPrivileges && parseInt(`$(id -u)`) == 0) {
    console.log("⚠️  Dropping root privileges for command execution");
    // Find a non-root user to run as
    let safeUser: string = "nobody";
    let userExists: string = "$(id ${safeUser} 2>/dev/null && echo "exists" || echo "missing")";
    if (userExists.trim() == "exists") {
      // Execute as safe user
      let result: string = "$(sudo -u ${safeUser} ${command} 2>&1)";
      console.log("✅ Command executed as ${safeUser}");
      return result;
    } else {
      console.log("❌ Safe user ${safeUser} not found, executing as root");
    }
  }
  // Execute normally
  let result: string = "$(${command} 2>&1)";
  return result;
}
// Example security checks
let securityContext: object = checkSecurityContext();
console.log("\nSecurity context:");
console.log(json.stringify(securityContext, true));
detectPrivilegeEscalation();
// Test secure execution
let testCommands: string[] = [
  "whoami",
  "id",
  "echo 'Safe command execution'"
];
for (let cmd: string in testCommands) {
  let result: string = executeSecurely(cmd, true);
  console.log("Command result: ${result.trim()}");
}
Network Security
Secure HTTP Requests
script.description("Secure HTTP request handling");
// Secure HTTP client
class SecureHttpClient {
  private allowedHosts: string[];
  private timeout: number;
  private maxRetries: number;
  constructor(allowedHosts: string[], timeoutSeconds: number = 30, maxRetries: number = 3) {
    this.allowedHosts = allowedHosts;
    this.timeout = timeoutSeconds;
    this.maxRetries = maxRetries;
  }
  private validateUrl(url: string): boolean {
    // Check protocol
    if (!url.startsWith("https://")) {
      console.log("❌ Only HTTPS URLs are allowed");
      return false;
    }
    // Extract hostname
    let hostname: string = url.replace("https://", "").split("/")[0].split(":")[0];
    // Check against allowed hosts
    let isAllowed: boolean = false;
    for (let allowedHost: string in this.allowedHosts) {
      if (hostname == allowedHost || hostname.endsWith(".${allowedHost}")) {
        isAllowed = true;
        break;
      }
    }
    if (!isAllowed) {
      console.log("❌ Host not in allowed list: ${hostname}");
      return false;
    }
    // Check for suspicious characters
    if (url.contains(" ") || url.contains("\n") || url.contains("\r")) {
      console.log("❌ URL contains suspicious characters");
      return false;
    }
    return true;
  }
  private sanitizeHeaders(headers: object): object {
    let sanitized: object = {};
    let headerNames: string[] = json.keys(headers);
    for (let headerName: string in headerNames) {
      let headerValue: string = json.getString(headers, ".${headerName}");
      // Remove potential injection characters
      let cleanValue: string = headerValue.replace(/[\r\n]/g, "");
      // Validate header name
      if (headerName.match(/^[a-zA-Z0-9-]+$/)) {
        sanitized = json.set(sanitized, ".${headerName}", cleanValue);
      } else {
        console.log("⚠️  Skipping invalid header name: ${headerName}");
      }
    }
    return sanitized;
  }
  get(url: string, headers: object = {}): object {
    console.log("Making secure GET request to: ${url}");
    if (!this.validateUrl(url)) {
      return {
        "success": false,
        "error": "URL validation failed",
        "status_code": 0
      };
    }
    let sanitizedHeaders: object = this.sanitizeHeaders(headers);
    // Build curl command with security options
    let curlCmd: string = "curl -s -L -k --max-time ${this.timeout} --max-redirs 3";
    // Add headers
    let headerNames: string[] = json.keys(sanitizedHeaders);
    for (let headerName: string in headerNames) {
      let headerValue: string = json.getString(sanitizedHeaders, ".${headerName}");
      curlCmd += " -H "${headerName}: ${headerValue}"";
    }
    // Add response format options
    curlCmd += " -w '{"http_code":"%{http_code}","time_total":"%{time_total}","size_download":"%{size_download}"}' "${url}"";
    let attempt: number = 0;
    while (attempt < this.maxRetries) {
      attempt++;
      console.log("Attempt ${attempt}/${this.maxRetries}");
      let startTime: number = parseInt(`$(date +%s%3N)`);
      let result: string = "$(${curlCmd} 2>/dev/null || echo '{"http_code":"000","time_total":"0","size_download":"0"}')";
      let endTime: number = parseInt(`$(date +%s%3N)`);
      try {
        let metrics: object = json.parse(result.split('\n').pop() || "{}");
        let httpCode: string = json.getString(metrics, ".http_code");
        if (httpCode.startsWith("2")) {
          console.log("✅ Request successful: ${httpCode}");
          return {
            "success": true,
            "status_code": parseInt(httpCode),
            "response_time_ms": endTime - startTime,
            "curl_time": parseFloat(json.getString(metrics, ".time_total")) * 1000,
            "size_bytes": parseInt(json.getString(metrics, ".size_download")),
            "attempt": attempt
          };
        } else if (httpCode == "000") {
          console.log("❌ Network error on attempt ${attempt}");
        } else {
          console.log("❌ HTTP error ${httpCode} on attempt ${attempt}");
          // Don't retry on client errors
          if (httpCode.startsWith("4")) {
            break;
          }
        }
      } catch {
        console.log("❌ Failed to parse response on attempt ${attempt}");
      }
      if (attempt < this.maxRetries) {
        let backoff: number = attempt * 2;
        console.log("Waiting ${backoff} seconds before retry...");
        "$(sleep ${backoff})";
      }
    }
    return {
      "success": false,
      "error": "All retry attempts failed",
      "status_code": 0,
      "attempts": attempt
    };
  }
}
// Example usage
let httpClient: SecureHttpClient = new SecureHttpClient(
  ["httpbin.org", "jsonplaceholder.typicode.com", "api.github.com"],
  30,
  3
);
// Test secure requests
let testUrls: string[] = [
  "https://httpbin.org/json",
  "https://httpbin.org/status/200",
  "https://evil.com/malicious",  // Not in allowed hosts
  "http://httpbin.org/json",     // HTTP not allowed
  "https://httpbin.org/status/500"  // Server error
];
for (let url: string in testUrls) {
  console.log("\n--- Testing URL: ${url} ---");
  let response: object = httpClient.get(url, {
    "User-Agent": "Utah-Secure-Client/1.0",
    "Accept": "application/json"
  });
  console.log("Result: ${json.stringify(response, true)}");
}
Best Practices Summary
Security Checklist
script.description("Comprehensive security checklist for Utah scripts");
// Security audit function
function performSecurityAudit(): object {
  console.log("Performing comprehensive security audit...");
  let audit: object = {
    "timestamp": `$(date -Iseconds)`,
    "audit_version": "1.0",
    "checks": {},
    "recommendations": [],
    "score": 0,
    "max_score": 0
  };
  let score: number = 0;
  let maxScore: number = 0;
  let recommendations: string[] = [];
  // Check 1: User privileges
  maxScore++;
  if (parseInt(`$(id -u)`) != 0) {
    score++;
    audit = json.set(audit, ".checks.non_root_execution", true);
  } else {
    audit = json.set(audit, ".checks.non_root_execution", false);
    recommendations.push("Avoid running scripts as root when possible");
  }
  // Check 2: File permissions
  maxScore++;
  let scriptFile: string = `$0`;
  if (fs.exists(scriptFile)) {
    let perms: string = "$(stat -c %a "${scriptFile}")";
    if (perms == "750" || perms == "755") {
      score++;
      audit = json.set(audit, ".checks.secure_script_permissions", true);
    } else {
      audit = json.set(audit, ".checks.secure_script_permissions", false);
      recommendations.push("Set secure permissions (750/755) on script files");
    }
  }
  // Check 3: Environment variable security
  maxScore++;
  let hasSecureEnv: boolean = env.get("SECURE_MODE") == "true";
  audit = json.set(audit, ".checks.secure_environment", hasSecureEnv);
  if (hasSecureEnv) {
    score++;
  } else {
    recommendations.push("Set SECURE_MODE=true environment variable");
  }
  // Check 4: Input validation
  maxScore++;
  // This would be checked by static analysis in a real implementation
  audit = json.set(audit, ".checks.input_validation", true);
  score++; // Assume good for this example
  // Check 5: Error handling
  maxScore++;
  // Check if script.exitOnError is used
  audit = json.set(audit, ".checks.error_handling", true);
  score++; // Assume good for this example
  // Check 6: Logging security
  maxScore++;
  let logDir: string = "/var/log";
  if (fs.exists(logDir)) {
    let logDirPerms: string = "$(stat -c %a "${logDir}")";
    if (logDirPerms == "755" || logDirPerms == "750") {
      score++;
      audit = json.set(audit, ".checks.secure_logging", true);
    } else {
      audit = json.set(audit, ".checks.secure_logging", false);
      recommendations.push("Ensure log directories have secure permissions");
    }
  } else {
    score++; // No logging directory, assume secure
    audit = json.set(audit, ".checks.secure_logging", true);
  }
  // Calculate final score
  let percentage: number = Math.round((score / maxScore) * 100);
  audit = json.set(audit, ".score", score);
  audit = json.set(audit, ".max_score", maxScore);
  audit = json.set(audit, ".percentage", percentage);
  audit = json.set(audit, ".recommendations", recommendations);
  return audit;
}
// Security guidelines
function printSecurityGuidelines(): void {
  console.log(`
🔒 Utah Security Best Practices:
1. **Input Validation**
   - Validate all user inputs
   - Sanitize command arguments
   - Use allowlists over blocklists
   - Check file paths for directory traversal
2. **Command Injection Prevention**
   - Never construct commands with user input
   - Use Utah's built-in functions when possible
   - Validate and sanitize all external data
3. **File System Security**
   - Set restrictive file permissions (600/640/750)
   - Validate file paths before access
   - Create backups before modifications
   - Use secure temporary directories
4. **Credential Management**
   - Never hardcode secrets in scripts
   - Use encrypted credential storage
   - Rotate credentials regularly
   - Limit credential scope and lifetime
5. **Network Security**
   - Use HTTPS for all external requests
   - Validate SSL certificates
   - Implement request timeouts
   - Restrict allowed hosts/domains
6. **Process Security**
   - Run with minimal privileges
   - Drop root privileges when possible
   - Monitor for privilege escalation
   - Use secure environment variables
7. **Error Handling**
   - Don't expose sensitive data in errors
   - Log security events appropriately
   - Fail securely by default
   - Implement proper cleanup on errors
8. **Audit and Monitoring**
   - Log security-relevant events
   - Regular security audits
   - Monitor file permission changes
   - Track credential usage
`);
}
// Perform security audit
let auditResults: object = performSecurityAudit();
console.log("\n=== SECURITY AUDIT RESULTS ===");
console.log(json.stringify(auditResults, true));
let percentage: number = json.getNumber(auditResults, ".percentage");
if (percentage >= 80) {
  console.log("✅ Good security posture: ${percentage}%");
} else if (percentage >= 60) {
  console.log("⚠️  Moderate security posture: ${percentage}%");
} else {
  console.log("❌ Poor security posture: ${percentage}%");
}
printSecurityGuidelines();
Next Steps
- Docker Integration - Secure containerized deployments
 - Cloud Automation - Cloud security best practices
 - System Administration - Apply security to system scripts
 
Security is paramount in automation scripts. These patterns and practices help build trustworthy, secure Utah applications that protect sensitive data and system resources.