{"record":{"id":"4f805b15c16c175f","repo":"stride3d/stride","slug":"relative-path-is-not-allowed-in-filesystemprovider","errorCode":null,"errorMessage":"Relative path is not allowed in FileSystemProvider.","messagePattern":"Relative path is not allowed in FileSystemProvider\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.IO/FileSystemProvider.cs","lineNumber":158,"sourceCode":"        end = -1;\n        return true;\n    }\n\n    /// <inheritdoc/>\n    public override string[] ListFiles(string url, string searchPattern, VirtualSearchOption searchOption)\n    {\n        return Directory.GetFiles(ConvertUrlToFullPath(url), searchPattern, (SearchOption)searchOption).Select(ConvertFullPathToUrl).ToArray();\n    }\n\n#if STRIDE_PLATFORM_IOS\n        public bool AutoSetSkipBackupAttribute { get; set; }\n#endif\n\n    /// <inheritdoc/>\n    public override Stream OpenStream(string url, VirtualFileMode mode, VirtualFileAccess access, VirtualFileShare share = VirtualFileShare.Read, StreamFlags streamType = StreamFlags.None)\n    {\n        if (localBasePath != null && url.Split(VirtualFileSystem.DirectorySeparatorChar, VirtualFileSystem.AltDirectorySeparatorChar).Contains(\"..\"))\n            throw new InvalidOperationException(\"Relative path is not allowed in FileSystemProvider.\");\n        var filename = ConvertUrlToFullPath(url);\n        var result = new FileStream(filename, (FileMode)mode, (FileAccess)access, (FileShare)share);\n\n#if STRIDE_PLATFORM_IOS\n            if (AutoSetSkipBackupAttribute && (mode == VirtualFileMode.CreateNew || mode == VirtualFileMode.Create || mode == VirtualFileMode.OpenOrCreate))\n            {\n                Foundation.NSFileManager.SetSkipBackupAttribute(filename, true);\n            }\n#endif\n\n        return result;\n    }\n\n    public override DateTime GetLastWriteTime(string url)\n    {\n        return File.GetLastWriteTime(ConvertUrlToFullPath(url));\n    }\n}","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.IO/FileSystemProvider.cs#L140-L176","documentation":"OpenStream rejects URLs containing '..' path segments when a local base path is set, because they could escape the provider's root directory. This is a deliberate path-traversal guard, not a file-system error.","triggerScenarios":"Calling OpenStream with a URL like \"../secrets.txt\" or \"assets/../../etc/passwd\" (on any separator style), while the provider has a non-null localBasePath.","commonSituations":"User-supplied filenames being opened directly, URLs joined from untrusted input, or legitimate relative paths that were never resolved to absolute form first.","solutions":["Resolve and normalize the URL to an absolute path before passing it to OpenStream","Sanitize user input: strip or reject '..' segments","Restructure code so files outside the base are accessed via a different provider, not traversal"],"exampleFix":"// before\nvar stream = provider.OpenStream($\"{userInput}\", VirtualFileMode.Open, VirtualFileAccess.Read);\n// after\nvar safe = Path.GetFullPath(Path.Combine(basePath, userInput));\nif (!safe.StartsWith(basePath)) throw new UnauthorizedAccessException();\nvar stream = provider.OpenStream(safe, VirtualFileMode.Open, VirtualFileAccess.Read);","handlingStrategy":"validation","validationCode":"bool isSafe = !url.Split('/', '\\\\').Contains(\"..\");\nif (!isSafe) throw new ArgumentException(\"Path traversal detected\");","typeGuard":null,"tryCatchPattern":"try { stream = provider.OpenStream(url, mode, access); }\ncatch (InvalidOperationException) { throw new UnauthorizedAccessException($\"Rejected path: {url}\"); }","preventionTips":["Treat all user-supplied path segments as untrusted","Resolve URLs to full paths and verify they stay under the base directory","Add a central sanitize helper for all file URL construction"],"tags":["io","security","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}