diff --git a/src/Umbraco.Web/Security/UmbracoAntiForgeryAdditionalDataProvider.cs b/src/Umbraco.Web/Security/UmbracoAntiForgeryAdditionalDataProvider.cs
new file mode 100644
index 0000000000..12d7cce753
--- /dev/null
+++ b/src/Umbraco.Web/Security/UmbracoAntiForgeryAdditionalDataProvider.cs
@@ -0,0 +1,91 @@
+using System;
+using Umbraco.Web.Mvc;
+using Umbraco.Core;
+using System.Web.Helpers;
+using System.Web;
+using Newtonsoft.Json;
+using System.ComponentModel;
+
+namespace Umbraco.Web.Security
+{
+ [Obsolete("This is no longer used and will be removed from the codebase in future versions")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class UmbracoAntiForgeryAdditionalDataProvider : IAntiForgeryAdditionalDataProvider
+ {
+ private readonly IAntiForgeryAdditionalDataProvider _defaultProvider;
+
+ ///
+ /// Constructor, allows wrapping a default provider
+ ///
+ ///
+ public UmbracoAntiForgeryAdditionalDataProvider(IAntiForgeryAdditionalDataProvider defaultProvider)
+ {
+ _defaultProvider = defaultProvider;
+ }
+
+ public string GetAdditionalData(HttpContextBase context)
+ {
+ return JsonConvert.SerializeObject(new AdditionalData
+ {
+ Stamp = DateTime.UtcNow.Ticks,
+ //this value will be here if this is a BeginUmbracoForms form
+ Ufprt = context.Items["ufprt"]?.ToString(),
+ //if there was a wrapped provider, add it's value to the json, else just a static value
+ WrappedValue = _defaultProvider?.GetAdditionalData(context) ?? "default"
+ });
+ }
+
+ public bool ValidateAdditionalData(HttpContextBase context, string additionalData)
+ {
+ if (!additionalData.DetectIsJson())
+ return false; //must be json
+
+ AdditionalData json;
+ try
+ {
+ json = JsonConvert.DeserializeObject(additionalData);
+ }
+ catch
+ {
+ return false; //couldn't parse
+ }
+
+ if (json.Stamp == default) return false;
+
+ //if there was a wrapped provider, validate it, else validate the static value
+ var validateWrapped = _defaultProvider?.ValidateAdditionalData(context, json.WrappedValue) ?? json.WrappedValue == "default";
+ if (!validateWrapped)
+ return false;
+
+ var ufprtRequest = context.Request["ufprt"]?.ToString();
+
+ //if the custom BeginUmbracoForms route value is not there, then it's nothing more to validate
+ if (ufprtRequest.IsNullOrWhiteSpace() && json.Ufprt.IsNullOrWhiteSpace())
+ return true;
+
+ //if one or the other is null then something is wrong
+ if (!ufprtRequest.IsNullOrWhiteSpace() && json.Ufprt.IsNullOrWhiteSpace()) return false;
+ if (ufprtRequest.IsNullOrWhiteSpace() && !json.Ufprt.IsNullOrWhiteSpace()) return false;
+
+ if (!UmbracoHelper.DecryptAndValidateEncryptedRouteString(json.Ufprt, out var additionalDataParts))
+ return false;
+
+ if (!UmbracoHelper.DecryptAndValidateEncryptedRouteString(ufprtRequest, out var requestParts))
+ return false;
+
+ //ensure they all match
+ return additionalDataParts.Count == requestParts.Count
+ && additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Controller] == requestParts[RenderRouteHandler.ReservedAdditionalKeys.Controller]
+ && additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Action] == requestParts[RenderRouteHandler.ReservedAdditionalKeys.Action]
+ && additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Area] == requestParts[RenderRouteHandler.ReservedAdditionalKeys.Area];
+ }
+
+ internal class AdditionalData
+ {
+ public string Ufprt { get; set; }
+ public long Stamp { get; set; }
+ public string WrappedValue { get; set; }
+ }
+
+ }
+}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 2fb54a2c80..01524e5962 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -341,6 +341,7 @@
+