K Khan
Sep 26, 2019
  3251
(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
Missing Properties tool for Optimizely CMS

If you have been working with Optimizely CMS for a while you have probably accumulated some technical debt in your property definitions. When you...

Per Nergård (MVP) | Mar 10, 2026

AI Generated Optimizely Developer Newsletter

Updates in the Optimizely ecosystem are everywhere: blog posts, forums, release notes, NuGet packages, and documentation changes. This newsletter...

Allan Thraen | Mar 10, 2026 |

Lessons from Building Production-Ready Opal Tools

AI tools are becoming a normal part of modern digital platforms. With  Optimizely Opal , teams can build tools that automate real tasks across the...

Praful Jangid | Mar 7, 2026

My Takeaway from Optimizely Opal Agents in Action 2026 - What Agentic AI Means for the Future of Digital Marketing

I would like to share with you what stayed in my head after this amazing virtual event organized by Optimizely. Agents in Action 2026 , a live...

Augusto Davalos | Mar 6, 2026