Skip to content

Commit

Permalink
Merge commit from fork
Browse files Browse the repository at this point in the history
Co-authored-by: Liran Tal <[email protected]>
  • Loading branch information
farnabaz and lirantal authored Feb 6, 2025
1 parent 8a59ae3 commit 9909773
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
20 changes: 19 additions & 1 deletion src/runtime/parser/utils/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,31 @@ export const unsafeLinkPrefix = [
'data:text/xml'
]

function isAnchorLinkAllowed(value: string) {
const decodedUrl = decodeURIComponent(value)
const urlSanitized = decodedUrl.replace(/&#x([0-9a-f]+);?/gi, '')
.replace(/&#(\d+);?/g, '')
.replace(/&[a-z]+;?/gi, '')

try {
const url = new URL(urlSanitized)
if (unsafeLinkPrefix.some(prefix => url.protocol.toLowerCase().startsWith(prefix))) {
return false
}
} catch {
return false
}

return true
}

export const validateProp = (attribute: string, value: string) => {
if (attribute.startsWith('on')) {
return false
}

if (attribute === 'href' || attribute === 'src') {
return !unsafeLinkPrefix.some(prefix => value.toLowerCase().startsWith(prefix))
return isAnchorLinkAllowed(value)
}

return true
Expand Down
29 changes: 28 additions & 1 deletion test/markdown/xss.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const md = `\
[XSS](vbscript:alert(document.domain))
<javascript:prompt(document.cookie)>
[x](y '<style>')
<a href="jav&#x09;ascript:alert('XSS');">Click Me</a>
<!-- image -->
Expand All @@ -31,7 +32,7 @@ const md = `\
`.trim()

it('XSS', async () => {
it('XSS generic payloads', async () => {
const { data, body } = await parseMarkdown(md)

expect(Object.keys(data)).toHaveLength(2)
Expand All @@ -41,3 +42,29 @@ it('XSS', async () => {
expect(Object.entries(props as Record<string, any>).every(([k, v]) => validateProp(k, v))).toBeTruthy()
}
})

it('XSS payloads with HTML entities should be caught', async () => {
const md = `\
## XSS payloads with HTML entities
<a href="jav&#x09;ascript:alert('XSS');">Click Me 1</a>
<a href="jav&#x0A;ascript:alert('XSS');">Click Me 2</a>
<a href="jav&#10;ascript:alert('XSS');">Click Me 3</a>
`.trim()

// set the number of assertions to expect
expect.assertions(4)

const { data, body } = await parseMarkdown(md)

expect(Object.keys(data)).toHaveLength(2)

for (const node of (body.children[1] as MDCElement).children) {
const props = (node as MDCElement).props || {}

if ((node as MDCElement).tag === 'a') {
expect(Object.keys(props)).toHaveLength(0)
}
}
})

0 comments on commit 9909773

Please sign in to comment.