CVE-2019-12277 (C#, published 2019-05-22T15:29Z)
Description: value: Blogifier 2.3 before 2019-05-11 does not properly restrict APIs, as demonstrated by missing checks for .. in a pathname.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/blogifierdotnet/Blogifier
Files changed:
src/Core/Api/AssetsController.cs
src/Core/CoreAPI.xml
src/Core/Extensions/StringExtensions.cs
src/Core/Services/StorageService.cs
Commit message: Tightening security in APIs


Vulnerable code:
                    items = await _store.Find(a => a.AssetType == AssetType.Image, pager);
                    items = await _store.Find(a => a.AssetType == AssetType.Attachment, pager);
                    items = await _store.Find(null, pager);
                items = await _store.Find(a => a.Title.Contains(search), pager);
        /// Upload file(s) to user data store
            Upload file(s) to user data store
        Task<IEnumerable<AssetItem>> Find(Func<AssetItem, bool> predicate, Pager pager, string path = "");
        public async Task<IEnumerable<AssetItem>> Find(Func<AssetItem, bool> predicate, Pager pager, string path = "")
            return fileName;
            return title.Replace("/", "");

Fixed code:
using Microsoft.AspNetCore.Authorization;
                    items = await _store.Find(a => a.AssetType == AssetType.Image, pager, "", !User.Identity.IsAuthenticated);
                    items = await _store.Find(a => a.AssetType == AssetType.Attachment, pager, "", !User.Identity.IsAuthenticated);
                    items = await _store.Find(null, pager, "", !User.Identity.IsAuthenticated);
                items = await _store.Find(a => a.Title.Contains(search), pager, "", !User.Identity.IsAuthenticated);
        /// Upload file(s) to user data store, authentication required
        [Authorize]
        [Authorize]
            Upload file(s) to user data store, authentication required
        public static string SanitizePath(this string str)
        {
            if (str.Contains("..") || str.Contains("//"))
                throw new ApplicationException("Invalid directory path");

            return str;
        }

        public static string SanitizeFileName(this string str)
        {
            if (str.Contains("..") || str.Contains("//") || str.Count(x => x == '.') > 1)
                throw new ApplicationException("Invalid file name");

            return str;
        }

        Task<IEnumerable<AssetItem>> Find(Func<AssetItem, bool> predicate, Pager pager, string path = "", bool sanitize = false);
        public async Task<IEnumerable<AssetItem>> Find(Func<AssetItem, bool> predicate, Pager pager, string path = "", bool sanitize = false)
            if (sanitize)
            {
                foreach (var p in page)
                {
                    p.Path = "";
                }
            }

            path = path.SanitizePath();

            return fileName.SanitizeFileName();
            return title.Replace("/", "").SanitizeFileName();