namespace Nexus.Api.Helpers; public static class PathSecurityHelper { /// Validates a path against directory traversal and resolves a safe absolute path. public static bool TryResolveSafePath(string basePath, string userInput, out string? safePath) { safePath = null; // URL-decode to catch encoded attacks like %2F, %2e%2e, %00 var decoded = Uri.UnescapeDataString(userInput); // Reject null bytes if (decoded.Contains('\0')) return false; // Combine with base and resolve to canonical form var combined = Path.Combine(basePath, decoded); var full = Path.GetFullPath(combined); var canonicalBase = Path.GetFullPath(basePath); // Must stay within the allowed base directory if (!full.StartsWith(canonicalBase + Path.DirectorySeparatorChar) && full != canonicalBase) return false; safePath = full; return true; } /// Validates config filename against path-traversal; must be alphanumeric .md. public static bool IsValidConfigFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) return false; return System.Text.RegularExpressions.Regex.IsMatch(fileName, @"^[a-zA-Z0-9._-]+\.md$"); } }