Skip to main content

Prevent Against CSV Injection Attacks

  • 3 minutes to read

DevExpress Card View, Grid View, Pivot Grid, and Vertical Grid extensions allow you to export data in CSV format. The exported file may contain content that spreadsheet software (such as Microsoft Excel) interprets as a formula. These formulas can execute shell commands when a user opens the file. For example, the following formula runs the Windows Calculator:

console
=cmd|' /C calc'!'!A1'

DevExpress Grid-like extensions do not auto-encode executable content for the following reasons:

  • Microsoft Excel requires user permission to run executable content.
  • Encoding may unintentionally alter data, such as negative numbers or text values that start with the “=” character.

DevExpress ASP.NET MVC extensions include a built-in mechanism to encode executable content. During CSV export operations, this mechanism encloses values that start with “=”, “-“, “+”, “@“, or “” in quote characters. You should enable executable content encoding to protect your application against CSV injection attacks such as CWE-74.

#Encode Executable Content for All DevExpress Controls

To encode at the application level, set the EncodeCsvExecutableContent property to True in the Global.asax file:

void Application_Start(object sender, EventArgs e) { 
    DevExpress.Export.ExportSettings.EncodeCsvExecutableContent = DevExpress.Utils.DefaultBoolean.True;
} 

#Encode Executable Content for Specific DevExpress Controls

#Built-in Export Commands

The BeforeExport property allows you to access export settings when you execute our built-in Export to CSV command or call the client-side ExportTo method. To encode content, enable the EncodeExecutableContent export setting:

@Html.DevExpress().GridView(settings => {
    settings.Name = "gvExport";
    settings.CallbackRouteValues = new { Controller = "Exporting", Action = "ExportPartial" };
    settings.Columns.Add("CompanyName");
    settings.Columns.Add("City");
    settings.Columns.Add("Country");
    settings.Columns.Add("UnitPrice");
    settings.Columns.Add("Quantity");
    settings.Toolbars.Add(t => {
        t.Items.Add(GridViewToolbarCommand.ExportToCsv);
    });
    settings.SettingsExport.EnableClientSideExportAPI = true;
    settings.SettingsExport.ExcelExportMode = DevExpress.Export.ExportType.DataAware;
    settings.SettingsExport.BeforeExport = (s, e) => {
        (e.ExportOptions as DevExpress.XtraPrinting.CsvExportOptionsEx).EncodeExecutableContent = DefaultBoolean.True;
    };
}).Bind(Model).GetHtml()

#Custom Export Commands

DevExpress Grid-like extensions include server-side methods designed to export data to CSV. These methods accept a CsvExportOptions or CsvExportOptionsEx object that stores export settings. Enable this object’s EncodeExecutableContent setting to encode executable content:

using System.Linq;
using System.Web.Mvc;
using DevExpress.Web.Mvc;

namespace MyProject.Controllers {
    public class HomeController : Controller {
        public ActionResult Index() {
            ViewBag.GridSettings = GetGridSettings();
            return View();
        }
        MyProject.Models.northwindEntities db = new MyProject.Models.northwindEntities();
        // Handles GridView callbacks
        [ValidateInput(false)]
        public ActionResult GridViewPartial() {
            ViewBag.GridSettings = GetGridSettings();
            var model = db.Products;
            return PartialView("_GridViewPartial", model.ToList());
        }
        // Sends a CSV document with the exported Grid as a response
        public ActionResult ExportTo() {
            var model = db.Products;
            var options = new CsvExportOptionsEx();
            options.EncodeExecutableContent = DefaultBoolean.True;
            return GridViewExtension.ExportToCsv(GetGridSettings(), model.ToList(), options);
        }
        // Returns exported GridView settings
        private GridViewSettings GetGridSettings() {
            var settings = new GridViewSettings();
            settings.Name = "GridView";
            settings.CallbackRouteValues = new { Controller = "Home", Action = "GridViewPartial" };
            settings.SettingsExport.FileName = "Report.csv";
            settings.KeyFieldName = "ProductID";
            settings.Columns.Add("ProductName");
            settings.Columns.Add("UnitPrice");
            settings.Columns.Add("QuantityPerUnit");
            settings.Columns.Add("Discontinued", MVCxGridViewColumnType.CheckBox);
            return settings;
        }
    }
}
@Html.Action("GridViewPartial")

@* When a user clicks this button, the button sends a callback to the "ExportTo" action and the server 
sends the resulting export file as a response *@
@Html.DevExpress().Button(settings => {
    settings.Name = "Button";
    settings.UseSubmitBehavior = false;
    settings.Text = "Export to CSV";
    settings.RouteValues = new { Controller = "Home", Action = "ExportTo" };
}).GetHtml()
@{
    var grid = Html.DevExpress().GridView(ViewBag.GridSettings);
}
@grid.Bind(Model).GetHtml()