diff --git a/src/routes/notes/mysql2/+page.md b/src/routes/notes/mysql2/+page.md index 5324a2b..46ad01d 100644 --- a/src/routes/notes/mysql2/+page.md +++ b/src/routes/notes/mysql2/+page.md @@ -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 diff --git a/src/routes/notes/react-spread/+page.md b/src/routes/notes/react-spread/+page.md new file mode 100644 index 0000000..404ad21 --- /dev/null +++ b/src/routes/notes/react-spread/+page.md @@ -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 ( +

hello world"}} /> +) +``` + +Which is different from how for example svelte handles it - by using a different tag / template (the equivalent would be `

{@html "..."}

`). + +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 ( + +) +``` + +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 () +} + +function Component({ props, key }) { + return ( +
+ Your key is {key || "empty"} +
+ ) +} +``` + +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]="pwned"` away from danger. +Check your vibe coded apps, and perhaps choose technologies with sane & safe defaults. \ No newline at end of file