Skip to content

Escape the prose-derived values that land in a title attribute - #1

Open
GetBeholder wants to merge 1 commit into
devfrom
fix/escape-prose-derived-values
Open

Escape the prose-derived values that land in a title attribute#1
GetBeholder wants to merge 1 commit into
devfrom
fix/escape-prose-derived-values

Conversation

@GetBeholder

Copy link
Copy Markdown
Owner

Same fix as GetBeholder/Beholder-ME#1 — this renderer carries the identical three sites.

colorTitle interpolated the colour word straight into a title="…" attribute, and both dmgTitle sites did the same with the damage word whenever it fell outside the known tiers and damageMeta echoed the raw prose word back as its label.

Every value on a slot comes from prose by way of the extractor, so a crafted value can close the attribute and add one of its own. Confirmed by rendering the payload into a real DOM and asking the parser: an injected onmouseover becomes an actual attribute node, not text. Every sibling label (colorSwatch, colorLabel, dmgLabel) already escaped — these three were an oversight.

Scope: three lines in paperdoll.js. No bundle to rebuild here; modules load directly.

Test: test/paperdoll_escaping.test.js renders eight prose-derived fields plus the character name with a breakout payload, in both views. Verified it fails against the previous code. Suite: 222 pass, 0 fail.

Output for well-formed values is unchanged.

Every value on a slot originates in prose and arrives through the extractor,
so by the time it reaches markup it is attacker-influenced. Two of them
reached a title="…" attribute unescaped:

  - the colour word, interpolated raw by colorTitle
  - the damage word, whenever it fell outside the known tiers and damageMeta
    echoed the raw prose word back as its label

A crafted value closes the attribute and adds one of its own; rendering a
payload into a real DOM and asking the parser confirms an injected event
handler becomes an actual attribute node. Every sibling label already escaped,
so this was an oversight rather than a choice.

The new test renders eight prose-derived fields plus the character name with a
breakout payload, in both views, and requires the raw payload never survives
into the markup. It fails against the previous code.

Output for well-formed values is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant