diff --git a/CSP/CSP.slnf b/CSP/CSP.slnf
new file mode 100644
index 000000000..d559cbaea
--- /dev/null
+++ b/CSP/CSP.slnf
@@ -0,0 +1,10 @@
+{
+ "solution": {
+ "path": "..\\..\\..\\AspNetCore.sln",
+ "projects": [
+ "src\\Middleware\\CSP\\src\\Microsoft.AspNetCore.Csp.csproj",
+ "src\\Middleware\\CSP\\test\\UnitTests\\Microsoft.AspNetCore.Csp.Test.csproj",
+ "src\\Middleware\\CSP\\test\\testassets\\CspMiddlewareWebSite.csproj",
+ ]
+ }
+}
\ No newline at end of file
diff --git a/CSP/README.md b/CSP/README.md
new file mode 100644
index 000000000..c2e7bbeef
--- /dev/null
+++ b/CSP/README.md
@@ -0,0 +1,38 @@
+# CSP
+
+## Description
+
+This directory contains .NET Core middleware for Content Security Policy (CSP). CSP is a very popular security mitigation against XSS and other injection vulnerabilities. CSP comes in many flavours, but we've chosen to add support for the most robust of them: nonce-based, strict-dynamic CSP.
+
+Design document: [Implementing CSP Support in .NET Core](https://docs.google.com/document/d/13NPKn65Wf1PdIwNL7H0cxhwmp2r8ZTe6vizXzO2HqY4/edit#)
+There was a previous discussion about CSP in .NET [here](https://github.com/dotnet/aspnetcore/issues/6001), that we have considered for our design.
+
+## Contributions
+This directory includes the following changes:
+
+* Allow configuration of whether CSP enabled in reporting or enforcement modes.
+* Allows configuration of a report URI, for violation reports sent by the browser.
+* CSP middleware generates a nonce-based, strict-dynamic policy.
+* Middleware adds the policy to HTTP responses according to the configuration.
+* Custom
+
+
+
+
Welcome
+
Learn about building Web apps with ASP.NET Core .
+
Click me!
+
+
diff --git a/CSP/test/testassets/CspApplication/Pages/Index.cshtml.cs b/CSP/test/testassets/CspApplication/Pages/Index.cshtml.cs
new file mode 100644
index 000000000..84d2a7b87
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/Index.cshtml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
+
+namespace CspApplication.Pages
+{
+ public class IndexModel : PageModel
+ {
+ private readonly ILogger _logger;
+
+ public IndexModel(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void OnGet()
+ {
+
+ }
+ }
+}
diff --git a/CSP/test/testassets/CspApplication/Pages/Privacy.cshtml b/CSP/test/testassets/CspApplication/Pages/Privacy.cshtml
new file mode 100644
index 000000000..46ba96612
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/Privacy.cshtml
@@ -0,0 +1,8 @@
+@page
+@model PrivacyModel
+@{
+ ViewData["Title"] = "Privacy Policy";
+}
+@ViewData["Title"]
+
+Use this page to detail your site's privacy policy.
diff --git a/CSP/test/testassets/CspApplication/Pages/Privacy.cshtml.cs b/CSP/test/testassets/CspApplication/Pages/Privacy.cshtml.cs
new file mode 100644
index 000000000..567303dae
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/Privacy.cshtml.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
+
+namespace CspApplication.Pages
+{
+ public class PrivacyModel : PageModel
+ {
+ private readonly ILogger _logger;
+
+ public PrivacyModel(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void OnGet()
+ {
+ }
+ }
+}
diff --git a/CSP/test/testassets/CspApplication/Pages/Shared/_Layout.cshtml b/CSP/test/testassets/CspApplication/Pages/Shared/_Layout.cshtml
new file mode 100644
index 000000000..0f584c3ce
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/Shared/_Layout.cshtml
@@ -0,0 +1,47 @@
+
+
+
+
+
+ @ViewData["Title"] - CspApplication
+
+
+
+
+
+
+ @RenderBody()
+
+
+
+
+
+
+
+ @RenderSection("Scripts", required: false)
+
+
diff --git a/CSP/test/testassets/CspApplication/Pages/Shared/_ValidationScriptsPartial.cshtml b/CSP/test/testassets/CspApplication/Pages/Shared/_ValidationScriptsPartial.cshtml
new file mode 100644
index 000000000..5a16d80a9
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/Shared/_ValidationScriptsPartial.cshtml
@@ -0,0 +1,2 @@
+
+
diff --git a/CSP/test/testassets/CspApplication/Pages/_ViewImports.cshtml b/CSP/test/testassets/CspApplication/Pages/_ViewImports.cshtml
new file mode 100644
index 000000000..3c712194d
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/_ViewImports.cshtml
@@ -0,0 +1,4 @@
+@using CspApplication
+@namespace CspApplication.Pages
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
+@addTagHelper Microsoft.AspNetCore.Csp.NoncedScriptTagHelper, Microsoft.AspNetCore.Csp
diff --git a/CSP/test/testassets/CspApplication/Pages/_ViewStart.cshtml b/CSP/test/testassets/CspApplication/Pages/_ViewStart.cshtml
new file mode 100644
index 000000000..a5f10045d
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Pages/_ViewStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "_Layout";
+}
diff --git a/CSP/test/testassets/CspApplication/README.md b/CSP/test/testassets/CspApplication/README.md
new file mode 100644
index 000000000..abe8417fe
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/README.md
@@ -0,0 +1,5 @@
+This is an example application to show how to set up the CSP middleware and configure the policy, and then have our nonces propagate to the templated HTML.
+
+## How to run
+1. Change the project name to `CspMiddlewareWebSite` and change the `IIS Express` entry to `CspApplication`.
+2. If you get build errors that complain about missing DLLs, try `.\build.cmd` from the repo root. If you're still getting missing DLL errors for `Microsoft.AspNetCore.Mvc`, try navingating to `src\Mvc` and then running the `.\build.cmd` there. You might have to install Node and put it on your path for the compilation of ASP.NET MVC to work.
diff --git a/CSP/test/testassets/CspApplication/Startup.cs b/CSP/test/testassets/CspApplication/Startup.cs
new file mode 100644
index 000000000..ab292d46c
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/Startup.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Csp;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace CspApplication
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddCsp();
+ services.AddRazorPages();
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ // CSP configuration. Must come first because other middleware might skip any following middleware.
+ app.UseCsp(policyBuilder => policyBuilder.WithCspMode(CspMode.ENFORCING)
+ .WithReportingUri("/csp"));
+
+
+ // Not sure how many of these we absolutely need to do a basic templated HTML page with a reporting endpoint.
+ app.UseDeveloperExceptionPage();
+ app.UseStaticFiles();
+ app.UseRouting();
+ app.UseAuthorization();
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapRazorPages();
+ });
+ }
+
+ public static IWebHostBuilder CreateWebHostBuilder(string[] args)
+ {
+ return new WebHostBuilder()
+ .UseKestrel()
+ .UseIISIntegration();
+ }
+
+ public static void Main(string[] args)
+ {
+ var host = CreateWebHostBuilder(args).UseContentRoot(Directory.GetCurrentDirectory()).UseStartup().Build();
+ host.Run();
+ }
+ }
+}
diff --git a/CSP/test/testassets/CspApplication/appsettings.Development.json b/CSP/test/testassets/CspApplication/appsettings.Development.json
new file mode 100644
index 000000000..8983e0fc1
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/CSP/test/testassets/CspApplication/appsettings.json b/CSP/test/testassets/CspApplication/appsettings.json
new file mode 100644
index 000000000..d9d9a9bff
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/CSP/test/testassets/CspApplication/wwwroot/css/site.css b/CSP/test/testassets/CspApplication/wwwroot/css/site.css
new file mode 100644
index 000000000..e679a8ea7
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/wwwroot/css/site.css
@@ -0,0 +1,71 @@
+/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+for details on configuring this project to bundle and minify static web assets. */
+
+a.navbar-brand {
+ white-space: normal;
+ text-align: center;
+ word-break: break-all;
+}
+
+/* Provide sufficient contrast against white background */
+a {
+ color: #0366d6;
+}
+
+.btn-primary {
+ color: #fff;
+ background-color: #1b6ec2;
+ border-color: #1861ac;
+}
+
+.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
+ color: #fff;
+ background-color: #1b6ec2;
+ border-color: #1861ac;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+ font-size: 14px;
+}
+@media (min-width: 768px) {
+ html {
+ font-size: 16px;
+ }
+}
+
+.border-top {
+ border-top: 1px solid #e5e5e5;
+}
+.border-bottom {
+ border-bottom: 1px solid #e5e5e5;
+}
+
+.box-shadow {
+ box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
+}
+
+button.accept-policy {
+ font-size: 1rem;
+ line-height: inherit;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+ position: relative;
+ min-height: 100%;
+}
+
+body {
+ /* Margin bottom by footer height */
+ margin-bottom: 60px;
+}
+.footer {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ white-space: nowrap;
+ line-height: 60px; /* Vertically center the text there */
+}
diff --git a/CSP/test/testassets/CspApplication/wwwroot/favicon.ico b/CSP/test/testassets/CspApplication/wwwroot/favicon.ico
new file mode 100644
index 000000000..a3a799985
Binary files /dev/null and b/CSP/test/testassets/CspApplication/wwwroot/favicon.ico differ
diff --git a/CSP/test/testassets/CspApplication/wwwroot/js/example.js b/CSP/test/testassets/CspApplication/wwwroot/js/example.js
new file mode 100644
index 000000000..c0bc6fb32
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/wwwroot/js/example.js
@@ -0,0 +1 @@
+alert("I'm a link-loaded script!");
diff --git a/CSP/test/testassets/CspApplication/wwwroot/js/site.js b/CSP/test/testassets/CspApplication/wwwroot/js/site.js
new file mode 100644
index 000000000..580cf0f85
--- /dev/null
+++ b/CSP/test/testassets/CspApplication/wwwroot/js/site.js
@@ -0,0 +1,6 @@
+// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+// for details on configuring this project to bundle and minify static web assets.
+
+// Write your Javascript code.
+
+alert("I'm a link-loaded script!");