{"record":{"id":"99af30fb80803b5d","repo":"TechnitiumSoftware/DnsServer","slug":"the-application-name-is-invalid-applicationname","errorCode":null,"errorMessage":"The application name is invalid: {applicationName}","messagePattern":"The application name is invalid: (.+?)","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Applications/DnsApplicationManager.cs","lineNumber":379,"sourceCode":"            await Task.WhenAll(tasks);\n\n            RefreshAppObjectLists();\n        }\n\n        public async Task<DnsApplication> InstallApplicationAsync(string applicationName, Stream appZipStream)\n        {\n            foreach (char invalidChar in Path.GetInvalidFileNameChars())\n            {\n                if (applicationName.Contains(invalidChar))\n                    throw new DnsServerException(\"The application name contains an invalid character: \" + invalidChar);\n            }\n\n            if (_applications.ContainsKey(applicationName))\n                throw new DnsServerException(\"DNS application already exists: \" + applicationName);\n\n            string applicationFolder = Path.GetFullPath(Path.Combine(_appsPath, applicationName));\n            if (!applicationFolder.StartsWith(_appsPath + Path.DirectorySeparatorChar))\n                throw new DnsServerException(\"The application name is invalid: \" + applicationName);\n\n            if (Directory.Exists(applicationFolder))\n                Directory.Delete(applicationFolder, true);\n\n            Directory.CreateDirectory(applicationFolder);\n\n            //keep a copy of the zip file in the application folder for transferring to other nodes\n            await using (FileStream zipCopyStream = new FileStream(Path.Combine(applicationFolder, applicationName + \".zip\"), FileMode.Create, FileAccess.ReadWrite))\n            {\n                await appZipStream.CopyToAsync(zipCopyStream);\n\n                zipCopyStream.Position = 0;\n\n                await using (ZipArchive appZip = new ZipArchive(zipCopyStream, ZipArchiveMode.Read, false, Encoding.UTF8))\n                {\n                    try\n                    {\n                        await appZip.ExtractToDirectoryAsync(applicationFolder, true);","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Applications/DnsApplicationManager.cs#L361-L397","documentation":"Thrown by InstallApplicationAsync when the resolved absolute application folder does not start with _appsPath + DirectorySeparatorChar. It is a path-traversal guard: applicationName must resolve to a directory strictly inside the apps root.","triggerScenarios":"applicationName containing relative segments (..), rooted paths (C:\\x, /x), or OS-specific separators that, after Path.GetFullPath, escape _appsPath. On case-insensitive filesystems a different-cased prefix can also slip past StartsWith.","commonSituations":"User-supplied app name from a form/API not sanitized; names like '../existing', '\\\\?\\C:\\evil', or containing backslashes on Linux where _appsPath uses '/'. A name that exactly equals _appsPath (no child segment) also fails because the separator is appended.","solutions":["Reject names containing '..', Path.AltDirectorySeparatorChar, or any GetInvalidFileNameChars before calling InstallApplicationAsync.","Restrict names to a safe whitelist regex like ^[A-Za-z0-9._-]+$.","Verify Path.GetFullPath(Path.Combine(_appsPath, name)) + separator is still under _appsPath + separator before install.","On case-insensitive OSes, compare with StringComparison.OrdinalIgnoreCase after both paths are normalized."],"exampleFix":"// before\nawait appManager.InstallApplicationAsync(appName, zip);\n\n// after\nif (!System.Text.RegularExpressions.Regex.IsMatch(appName, @\"^[A-Za-z0-9._-]+$\"))\n    throw new ArgumentException(\"Invalid app name\", nameof(appName));\nawait appManager.InstallApplicationAsync(appName, zip);","handlingStrategy":"validation","validationCode":"static readonly Regex SafeName = new(@\"^[A-Za-z0-9._-]+$\");\nbool IsSafeAppName(string n) => !string.IsNullOrWhiteSpace(n) && SafeName.IsMatch(n) && !n.Contains(\"..\");","typeGuard":"static bool IsValidAppName(string name) =>\n    !string.IsNullOrWhiteSpace(name)\n    && System.Text.RegularExpressions.Regex.IsMatch(name, @\"^[A-Za-z0-9._-]+$\");","tryCatchPattern":"if (!IsValidAppName(name)) return BadRequest(\"Invalid app name\");\ntry { await mgr.InstallApplicationAsync(name, zip); }\ncatch (DnsServerException ex) when (ex.Message.Contains(\"name is invalid\")) { return BadRequest(ex.Message); }","preventionTips":["Whitelist app names to ^[A-Za-z0-9._-]+$ at the API/UI trust boundary.","Reject '..', slashes, and rooted segments before install.","Never pass user-supplied paths unmodified as applicationName."],"tags":["security","path-traversal","input-validation","dns-app"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}