K Khan
Sep 26, 2019
visibility 3480
star star star star star
(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

error Please login to comment.
Latest blogs
Copies vs. Connections: Modeling Content Areas for Multilingual Success

Starting With the Simple Question Most multilingual content modeling conversations start with a deceptively simple question from a client: "If we s...

Vipin Banka | Aug 23, 2026

Content Transfer coming to Optimizely SaaS CMS

Back in June I released Content Transfer on the Optimizely nuget feed – today I’m releasing version 1.0 , because we’ve had it running out in the...

Matt Pallatt | Aug 23, 2026

Improving Optimizely Product Information in LLM Tools

Tools like Claude Code can be great for working with Optimizely CMS, but when they index outdated or incomplete information about developing a...

Nicholas Sideras | Aug 21, 2026 |

How to Get a Bacpac Out of DXP (And Never Do It By Hand Again)

Every Optimizely DXP project eventually runs into the same task: getting production data onto a local machine so you can actually troubleshoot...

KennyG | Aug 20, 2026