add react spread notes

This commit is contained in:
Daniel Bulant 2025-07-06 15:31:01 +02:00
parent 004d08ad18
commit a0c424db77
No known key found for this signature in database
2 changed files with 68 additions and 0 deletions

View file

@ -4,6 +4,8 @@ tags: [security, javascript]
date: 2025-03-29
---
*note that this might have changed silently, though there is still an [open issue](https://github.com/sidorares/node-mysql2/issues/1247) referencing this*
TLDR object serialization via [sqlstring](https://www.npmjs.com/package/sqlstring), vulnerable if user input is not primitive (e.g. unchecked object).
```js

View file

@ -0,0 +1,66 @@
---
title: React spread operator is dangerous
tags: [cybersec]
date: 2025-07-06
---
Using spread operator within react with untrusted user input is a recipe for XSS; embedding raw HTML into website.
React supports embedding raw HTML via an attribute called `dangerouslySetInnerHTML.__html`.
```jsx
return (
<p dangerouslySetInnerHTML={{__html:"<b>hello world</b>"}} />
)
```
Which is different from how for example svelte handles it - by using a different tag / template (the equivalent would be `<p>{@html "..."}</p>`).
JSX supports spread operators just like any JS object, as it creates one under the hood anyway.
Which is nice for passing props to another component:
```jsx
return (
<Component {...props} />
)
```
But this could be coupled to make a mostly hidden bug with no 'danger' in it's sources being explicitly present:
```jsx
import { useSearchParams } from 'next/navigation';
import { parse } from 'qs';
function useQs() {
const searchParams = useSearchParams();
const search = searchParams.toString();
return parse(search, {
ignoreQueryPrefix: true,
decoder: (str) => {
str = decodeURIComponent(str);
return str
}
});
}
function Page() {
// load query string, i.e. parses http://tld/path?key=val into { key: "val" }
const qs = useQs();
return (<Component props={{ }} {...qs} />)
}
function Component({ props, key }) {
return (
<div {...props}>
Your key is {key || "empty"}
</div>
)
}
```
The above app is vulnerable, because the latter spread operator can override `props`, which is then spreaded `div`.
This would be safe - if buggy - if all we could do is set `props` to a string value.
But `qs` also parses objects. So you're just one `?props[dangerouslySetInnerHTML][__html]="<b>pwned</b>"` away from danger.
Check your vibe coded apps, and perhaps choose technologies with sane & safe defaults.