Vulnerability in EPiServer.Forms

Try our conversational search powered by Generative AI!

Anders Hattestad
Feb 1, 2011
(13 votes)

Know your enemy; Sun Tzu's The Art of War

If you wan to be able to archive your goals in a EPiServer project you need to know the product. And EPiServer have (thanks heaven) open dll’s so we can use reflector to browse thru the inner workings of the product. Sometime I guess they regret that decision, but I honestly think that's one of the things that make EPiServer as a product great.

Then back to topic, who can we know our enemy

A twitter user posted a tweet some days ago where he said: “Ohhh, I SOOO want an event to trigger when dynamic properties change. Please! #EPiServer

But instead of begging he should have tried to know his enemy, an start the all mighty reflector :)

AFAIK there are only one place dynamic properties are saved and that's in the EditDynProp.aspx. And that page have one button, called ApplyButton….


Here we see that there is a method SaveCollection that is called


And that calls a method Save


Which calls PopulatePropertyCommand



And here we see that OnBeforeSavingProperty is called


And here it is. BeforeSavingProperty, that's an event that get called when a dynamic property is saved. Either if it’s empty or have values. This event is only called when you save a dynamic property.

Code Snippet
  1. public class AttachEvents : PlugInAttribute
  2. {
  3.     public static void Start()
  4.     {
  5.         PageDB.BeforeSavingProperty += new EventHandler<PropertyEventArgs>(PageDB_BeforeSavingProperty);
  6.     }
  8.     static void PageDB_BeforeSavingProperty(object sender, PropertyEventArgs e)
  9.     {
  10.         int a = 0;
  11.     }

This opens up some nice things that can be done. For instance create a version list on dynamic property page. Which is one of the feature I miss most.

It this event was not there we could also used PageAdaptors to hook our self up to the ApplyButton click event and done it there.

This feature have been around since CMS 5 it seems. So happy coding and use your Reflector when you can :)

Feb 01, 2011


Feb 1, 2011 09:16 AM

Nice work Anders!

Feb 1, 2011 09:29 AM

There is a chance that the user (!) stopped looking when he saw the DynamicPropertiesDB class, which indicate a class in the EPiServer.DataAccess namespace. This namespace has traditionally been a "keep your dirty fingers away" kind of namespace.

However, it is now included in the SDK Reference (though documentation is missing.) This makes me wonder if we're actually allowed to use it now, which would have been nice for this particular feature at least.

Anyone care to pitch in?

Anders Hattestad
Anders Hattestad Feb 1, 2011 09:36 AM

It's probably true that the user in question stopped looking there :) (that lazy man :))
but events are public pr default, and if they exists they are usable.
If the founding fathers didn't want us to use them they could have used (Good forbid) protected internal delegates

Martin Helgesen
Martin Helgesen Feb 1, 2011 09:38 AM

Nice post Mr.Hattestad Feb 1, 2011 10:29 AM

If you look at the desciption for EPiServer.DataAccess namespace on it says:

"The EPiServer.DataAccess namespace contains internal classes that is only intended for internal functions in EPiServer, you should not use these classes because you will break compability with future upgrades. There is though one important enumeration that comes to use when publishing content using EPiServer.DataFactory."

PageDB is not a publically supported API. Use the workaround at your own risk!!

Anders Hattestad
Anders Hattestad Feb 1, 2011 10:54 AM

It is actully marked with public. :)
public class PageDB : DataAccessBase Feb 1, 2011 11:04 AM

There is a BIG difference between a Type being marked public and it being part of the publically supported API of a product. That's where the documentation overrides.

Feb 1, 2011 11:58 AM

Yeah; I agree on that lazy part.

I like to think of APIs like a forest. This is not specific to EPiServer in any way. You're allowed to wonder about, exploring things. But if you wonder too far off the path, you're likely to get lost. Reflector is your GPS, so to speak, so you can explore more than you could without it, but the dark forest can be a dangerous place never the less. Suddenly someone puts up a fence, or cuts down the trees, and then getting back to the path gets more difficult.

Upgrades, new functionality, hotfixes; they will from time to time demand breaking changes, that is the life of software. The effort put into keeping the most used parts of the API backwards compatible will always be greater than on the less used ones.

Solving complicated problems sometimes demand complicated solutions, using undocumented parts of the API, or changing how the system works in ways that is not optimal. But as Joel so eloquently puts it - "If it's this hard, maybe we're doing something wrong":

In this particular case, when using that event, we discovered that the event argument class had a property called CurrentPage, of the type PageReference. This is the first warning that something is not quite right. In all (I think) other places, CurrentPage is a PageData object. Also, the event seems to be triggered for non-modified properties, so it is a little sharp around the edges.

All in all, we're opting on not using this event, it does not feel quite right, and we want to keep the upgrade path as clean as possible. I did no see that usage description on the namespace, which makes this an even clearer no-no.

Lesson learned: just because you can do it does not mean you should.

Anders Hattestad
Anders Hattestad Feb 1, 2011 12:27 PM

Have no trouble seeing that this stuff can change, but

When I see a solution so easy as to just attach myself to an event I feel that we are doing something right :)

but I have no trouble seeing your point on upgrades and hot fixes.

Why do you mark other classes with internal then? :) Feb 1, 2011 12:52 PM

Anders =>

So we can use them in other projects if we like.

Feb 1, 2011 01:56 PM

In the case of these DataAccess-types, there is a need to reference them across other EPiServer "core"-assemblies, so "internal" wont work leaving not much choice but to mark them as "public". (something like c++'s "friend" would be nice to have sometimes).

When *those* requirements aren't needed, we sure do use "internal" as you probably have noticed ;-)


Feb 1, 2011 02:26 PM

[InternalsVisibleTo] :)

Frederik Vig
Frederik Vig Feb 1, 2011 02:28 PM

@Johan why not use the assemblyinfo file to mark which assemblies should have access to the internal marked class by using the InternalsVisibleTo attribute (


Anders Hattestad
Anders Hattestad Feb 1, 2011 02:30 PM

stop Fredrik don't give away methods on how to
Mark stuff internal... :)

Magnus Rahl
Magnus Rahl Feb 1, 2011 03:21 PM

I'm not picking sides here, just IMHO: It is still possible to access internal/private/whatever and to "new" non-virtual members, even though it gets hairy and ugly. So the access modifiers are mainly about expressing the /intended/ use of a class - something which /can/ be expressed by other means (like documentation). Nobody can build a framework which is perfectly extensible everywhere, especially not without introducing breaking changes as the core features are improved. Just because you can you shouldn't, with great (reflector) power comes great responsibility, jada-jada, etc. Or along the lines of Joel's very popular blog post: "If it's this hard, maybe we shouln't do it at all."

Maybe classes should have a [FeatureStability(x)] or [Hackability(x)] attribute conveying the estimated risk of a breaking change in future versions.

Anders Hattestad
Anders Hattestad Feb 1, 2011 03:22 PM

I would like to point out that I started this post about how changeable EPiServer is. And by changeable I think all know that sometimes our changes will not survive an upgrade. That’s the name of the game.

I think that is one of the primary EPiServer strengths!, And I hope that the development team have the same attitude :) [Dont use private/internal] Feb 1, 2011 04:35 PM

We have a lot of legacy code to deal with or technical debt as we call it here.

We now have a policy where we err on the side of openess (i.e. make classes public), extendability (i.e. make methods virtual) and testability (i.e. use interfaces and DI techniques). It will be a long time before this is felt in any great strength and of course mistakes get made. Keep your constructive feedback coming!

Please login to comment.
Latest blogs
Update related content

In this article, I will show simple code that allow to replace linked content with other content selected by the Editor. When deleting content whos...

Grzegorz Wiecheć | Dec 8, 2023 | Syndicated blog

Getting Started with Optimizely SaaS Core and Next.js Integration: Content Areas and Blocks

The blog guide elaborates on improving content rendering by exploring content areas and blocks within the Optimizely CMS. It walks through setting ...

Francisco Quintanilla | Dec 8, 2023 | Syndicated blog

Maximize performance by uploading your external data to Optimizely Graph

Learn to integrate external data into Optimizely Graph for improved performance, covering data preparation, synchronization, and effective querying.

Surjit Bharath | Dec 6, 2023 | Syndicated blog

Google Read Aloud Reload Problems

Inclusive web experiences greatly benefit from accessibility features such as Google Read Aloud. This tool, which converts text into speech, enable...

Luc Gosso (MVP) | Dec 4, 2023 | Syndicated blog