A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

K Khan
Sep 26, 2019
  3095
(1 votes)

EPiServer FileUpload element - Allowed extensions check isn't enough

EPiServer Forms FileUpload element provides a property with the name 'Allowed extensions', that enables content editors to allow website users to upload files in the required format. This can be spoofed easily e.g with value PDF only for allowed extension I am allowed to upload pdf files along with Funny-jpg.pdf also (I hope you got what I meant ;) ). It's a High-security risk for the sites that accept files from end-users via EPiServer forms. I have to come up with an immediate solution, hope this will help someone else also.

1 - extend FileUploadElementBlock (I was Lucky as already had an extended element in our code)

public class StyledFileUploadElementBlock : FileUploadElementBlock
    {
        public override string Validators
        {
            get
            {
                var customValidator = typeof(FileContentTypeCustomValidator).FullName;
                var validators = this.GetPropertyValue(content => content.Validators);
                if (string.IsNullOrEmpty(validators))
                {
                    return customValidator;
                }
                else
                {
                    return string.Concat(validators, EPiServer.Forms.Constants.RecordSeparator, customValidator);
                }
            }
            set
            {
                this.SetPropertyValue(content => content.Validators, value);
            }
        }
    }

2 - Write a service that could look into file signatures and could determine File Type based on the File Contents, not just extension. 

Get file type by signatures

3 - Add your business logic for your custom validator

public class FileContentTypeCustomValidator : ElementValidatorBase
    {
        private Injected<IFileValidationService> _fileService;
        protected IFileValidationService FileValidationService { get { return _fileService.Service; } }

        public override bool? Validate(IElementValidatable targetElement)
        {
            StyledFileUploadElementBlock fileUploadElementBlock = targetElement as StyledFileUploadElementBlock;
            if (fileUploadElementBlock == null)
                return true;
            var files = targetElement?.GetSubmittedValue();
            if (files == null)
                return true;
            var postedFiles = files as List<HttpPostedFile>;
            if (postedFiles != null && postedFiles.Any())
            {
                foreach (var httpPostedFile in postedFiles)
                {
//Your Business logic
                    var fileType = FileValidationService.GetFileType(httpPostedFile.InputStream);
                    if (string.IsNullOrEmpty(fileType.Extension))
                        return false;

                    if (!fileUploadElementBlock.FileExtensions.Contains(fileType.Extension))
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        public override bool AvailableInEditView
        {
            get
            {
                return false;
            }
        }

        /// 
        public override IValidationModel BuildValidationModel(IElementValidatable targetElement)
        {
            StyledFileUploadElementBlock fileUploadElementBlock = targetElement as StyledFileUploadElementBlock;
            if (fileUploadElementBlock == null)
            {
                return base.BuildValidationModel(targetElement);
            }

            var fileExtensions = fileUploadElementBlock.FileExtensions;
            if (base._model != null) return base._model;

            string validatorMessage = base._validationService.Service.GetValidatorMessage(base.GetType(), (fileExtensions.Split(new string[1]
            {
                ","
            }, StringSplitOptions.RemoveEmptyEntries).Length != 0) ? "allowedextensionsmessage" : string.Empty);
            base._model = new AllowedExtensionsValidationModel
            {
                Accept = fileExtensions,
                Message = string.Format(validatorMessage, fileExtensions)
            };

            return base._model;
        }
    }


Stay Safe!

EPiServer Forms version: 4.25.0

Sep 26, 2019

Comments

Please login to comment.
Latest blogs
Looking back at Optimizely in 2025

Explore Optimizely's architectural shift in 2025, which removed coordination cost through a unified execution loop. Learn how agentic Opal AI and...

Andy Blyth | Dec 17, 2025 |

Cleaning Up Content Graph Webhooks in PaaS CMS: Scheduled Job

The Problem Bit of a niche issue, but we are building a headless solution where the presentation layer is hosted on Netlify, when in a regular...

Minesh Shah (Netcel) | Dec 17, 2025

A day in the life of an Optimizely OMVP - OptiGraphExtensions v2.0: Enhanced Search Control with Language Support and Synonym Slots

Supercharge your Optimizely Graph search experience with powerful new features for multilingual sites and fine-grained search tuning. As search...

Graham Carr | Dec 16, 2025

A day in the life of an Optimizely OMVP - Optimizely Opal: Specialized Agents, Workflows, and Tools Explained

The AI landscape in digital experience platforms has shifted dramatically. At Opticon 2025, Optimizely unveiled the next evolution of Optimizely Op...

Graham Carr | Dec 16, 2025