
Okay, maybe not all code and not always. This is just a short note on the prototype pollution as I have seen this issue again and again.
Photo byMaxim Tolchinskiy onUnsplash
What is this about?
If you use JavaScriptObject-bracket notation that accepts input from users then you may already have introduced Prototype pollution to your code. See this very simplified example:
constinternal={foo:{bar:null}}constacceptUserInput=(type,subtype,value)=>{internal[type][subtype]=value}
Applied:
// no problem so far, this is the expected inputacceptUserInput('foo','bar','I am so clever')// malicious inputacceptUserInput('__proto__','polluted','Bon jour 🐻❄️')
The result of the malicious input is, that all your newly created objects do now contain thepolluted
property and the polar bear greets you:
constobj={}console.debug(obj.polluted)// 'Bon jour 🐻❄️'
Why is this a problem?
On the client this is somewhat to less problematic but on the server this can open doors to follow-up attacks.
Let's say an attacker knows, that you use a runtime-created Object wihtoutObject.create(null)
during your checks for certain access privileges (which you should not do but I need an example here).
With the prototype pollution they could unlock privileges and gain more access on your system than they should:
constinternal={foo:{bar:null}}constacceptUserInput=(type,subtype,value)=>{internal[type][subtype]=value}// assume, this object// is constructed when reading// values from dbconstgetRoles=()=>({canAccessThat:true})constuserCanAccessThis=()=>{constme=getCurrentUser()// get from session etc.constroles=getRoles(me.id)returnroles.canAccessThis===true}// malicious inputacceptUserInput('__proto__','canAccessThis',true)// will now always return true for every useruserCanAccessThis()
This is, again, a simplified example but I hope you can see the severity it could introduce into your system.
What can I do to prevent it?
- Reduce Object-bracket notation and use dot notation where possible
- Alternatively use a
Map
or aSet, depending on your use-case - Beware of deep merging objects without checking that no properties of the prototype chain are affected
- Validate inputs, especially if on the server
- Use
Object.create(null)
to create Objects with no prototype
Thank you and please let me know, if you have any issues with the article or simply if you liked it and it helped you.
Top comments(15)

- LocationCity of Bath, UK 🇬🇧
- Education11 plus years* active enterprise development experience and a Fine art degree 🎨
- WorkWeb Development Consultant at ForgeRock
- Joined
Okay I can see a small potential risk here, thank you for showing me why automatic prototypical inheritance could be exploited.
My 2 cents:
I think that the prevention ideas may be idealism fodder for the developer who doesn't yet understand the significance and there is potential to just blindly add this sort of complexity to every single thing (trust me, I was that guy)
Could it be that the best way to prevent this sort of attack is a logical problem rather than a way of using js, for example some sort of 2 step permission system with a key that can only be issued from the server side to prove permissions
Better yet, don't role your own permission system and use Oauth and OpenID

- LocationBremen, Germany
- EducationM.Sc.
- Pronounshe/him
- WorkScientific Employee at University of Bremen
- Joined
I know the permission example is a bit drastic, but I also think it's a good way to especially show beginners how far this can get hypothetically.
I am also convinced, that this is indeed also related of how people use JS. For example: articles, I read about "why you should not useswitch
", sometimes propose to use a dictionary-like Object as in the example above. It's also a very fast approach, compared to use am Map.
Maybe I also add, that many popular libraries (lodash, underscore) are known to habe introduced PP im prior versions?

- LocationCity of Bath, UK 🇬🇧
- Education11 plus years* active enterprise development experience and a Fine art degree 🎨
- WorkWeb Development Consultant at ForgeRock
- Joined
The thing is I looked at your example and initially I was sceptical, the more I looked the more I saw this could happen. I like this post I ranked it as high quality so I hope you can have more discussions from that.
Oh yes, I know the pain that is lodash or similar, the security argument against a community authored std library is a juicy topic, worth writing about?
Poor misundrstood switch, I think there is some anti statement sentiment stemming from the FP community the myth that FP never uses statements, that and the similar looking branches I guess, again I had never considered this might be another reason why switch is the healthy choice.
Much food for thought here!

- LocationGermany
- Pronounshe/him
- WorkSelf Employed and Gov contracted Platforms Engineer, Software Architect & Administrator
- Joined
hasOwnProperty or "in" should be used here or indeed a set or map..
alternatively a lookup table.
why would I blindly trust user input.. that's trivial basic knowledge.. I always have to know all possible options a user might use and discard the excess.

- LocationBremen, Germany
- EducationM.Sc.
- Pronounshe/him
- WorkScientific Employee at University of Bremen
- Joined
You should, of course, never trust user input. But you should also not solely rely on validation, thus taking this scenario as seriously as other scenarios. Validation can fail and you never can cover all edge cases during validation.
Edit: note, thatin
is not safe, either:
'__proto__'in{}// true
I summarized a few of these issues in one of my other articles:How to mess up your JavaScript code like a boss

- LocationGermany
- Pronounshe/him
- WorkSelf Employed and Gov contracted Platforms Engineer, Software Architect & Administrator
- Joined
for some reason that's precisely why I mentionedhasOwnProperty
first, becausein
CAN be used in cases you are checking against known keys.
also.. when validation fails, it should fail.
that's why it is called validation..

- LocationCalifornia
- EducationNetworking/Software
- WorkSelf Employed
- Joined
Would like to see a breakdown of this topic on more common operations like saving user settings as a JSON object to the database. Like what would happen if prototype pollution was saved to the database by mistake then hydrated in the browser?
Devs tend to pay close attention to security features but forget about security on the random features like user settings, or repeatable fields.

- LocationBremen, Germany
- EducationM.Sc.
- Pronounshe/him
- WorkScientific Employee at University of Bremen
- Joined
Thanks that would be a great follow-up article. Let me check the next days what I can find.

- LocationWürzburg, Germany
- WorkUsability Engineer & Frontend Developer
- Joined
I never understood why one would use Object.create(null) now I do. Thank you.

- LocationBremen, Germany
- EducationM.Sc.
- Pronounshe/him
- WorkScientific Employee at University of Bremen
- Joined
You literally got me on this one. Now please take a few minutes and review my other articles that contain hours of research and writing effort and compare their likes with this one. Something is really broken here. Still, I tried to deliver on the topic as good as possible!

- LocationBremen, Germany
- EducationM.Sc.
- Pronounshe/him
- WorkScientific Employee at University of Bremen
- Joined
I think you misunderstood completely. Sorry.
For further actions, you may consider blocking this person and/orreporting abuse