All your JavaScript code is polluted
Jan Küster
Posted on November 8, 2022
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 by Maxim Tolchinskiy on Unsplash
What is this about?
If you use JavaScript Object-bracket notation that accepts input from users then you may already have introduced Prototype pollution to your code. See this very simplified example:
const internal = {
foo: {
bar: null
}
}
const acceptUserInput = (type, subtype, value) => {
internal[type][subtype] = value
}
Applied:
// no problem so far, this is the expected input
acceptUserInput('foo', 'bar', 'I am so clever')
// malicious input
acceptUserInput('__proto__', 'polluted', 'Bon jour 🐻❄️')
The result of the malicious input is, that all your newly created objects do now contain the polluted
property and the polar bear greets you:
const obj = {}
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 wihtout Object.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:
const internal = {
foo: {
bar: null
}
}
const acceptUserInput = (type, subtype, value) => {
internal[type][subtype] = value
}
// assume, this object
// is constructed when reading
// values from db
const getRoles = () => ({ canAccessThat: true })
const userCanAccessThis = () => {
const me = getCurrentUser() // get from session etc.
const roles = getRoles(me.id)
return roles.canAccessThis === true
}
// malicious input
acceptUserInput('__proto__', 'canAccessThis', true)
// will now always return true for every user
userCanAccessThis()
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 a Set, 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.
Posted on November 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 19, 2024
October 30, 2024