Skip to content

Commit 5e200f1

Browse files
committed
fix: text matching Object.prototype property names silently not rendered
Fixes #746. `graphemeImages` was created as a plain object via `{ ...options.graphemeImages }`, which means it inherits from `Object.prototype`. When the text being rendered exactly matches an inherited property name (e.g. "constructor", "toString", "valueOf", "hasOwnProperty"), the lookup `graphemeImages[text]` returned the inherited method instead of `undefined`. Downstream code then treated that function as an image URL and emitted `<image href="function Object() { [native code] }" ...>` instead of rendering the text as glyph paths. The fix changes the backing storage to a null-prototype object via `Object.assign(Object.create(null), options.graphemeImages)`. Bracket lookups for non-own properties now return `undefined` as expected, and the text falls through to the normal glyph-rendering path. No behaviour change for legitimate emoji/image keys. Test plan: new case in `test/emoji.test.tsx` that renders the text "constructor toString valueOf" without any graphemeImages and asserts the SVG contains no `[native code]`, `[object Object]`, or `<image>` element. All existing emoji and basic tests continue to pass.
1 parent ab49faf commit 5e200f1

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

src/satori.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,14 @@ export default async function satori(
7373
root.setJustifyContent(Yoga.JUSTIFY_FLEX_START)
7474
root.setOverflow(Yoga.OVERFLOW_HIDDEN)
7575

76-
const graphemeImages = { ...options.graphemeImages }
76+
// Null-prototype object so that `graphemeImages[text]` lookups for strings
77+
// that match `Object.prototype` property names (e.g. "constructor",
78+
// "toString", "valueOf") return `undefined` instead of inherited methods.
79+
// See https://github.com/vercel/satori/issues/746.
80+
const graphemeImages: Record<string, string> = Object.assign(
81+
Object.create(null),
82+
options.graphemeImages
83+
)
7784
// Some Chinese characters have different glyphs in Chinese and
7885
// Japanese, but their Unicode is the same. If the user needs to display
7986
// the Chinese and Japanese characters simultaneously correctly, the user

test/emoji.test.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,18 @@ describe('Emojis', () => {
116116

117117
expect(await toImage(svg)).toMatchImageSnapshot()
118118
})
119+
120+
// https://github.com/vercel/satori/issues/746
121+
it('should render text that matches Object.prototype property names', async () => {
122+
const svg = await satori(<div>constructor toString valueOf</div>, {
123+
width: 200,
124+
height: 100,
125+
fonts,
126+
})
127+
// The text used to be silently replaced with the inherited prototype
128+
// method, e.g. `<image href="function Object() { [native code] }" .../>`.
129+
expect(svg).not.toContain('[native code]')
130+
expect(svg).not.toContain('[object Object]')
131+
expect(svg).not.toContain('<image ')
132+
})
119133
})

0 commit comments

Comments
 (0)