Skip to content

Commit

Permalink
fix: disable parsing javascript: links, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nperez0111 committed May 16, 2024
1 parent 980b54f commit 738c436
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 5 deletions.
14 changes: 13 additions & 1 deletion packages/extension-link/src/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,22 @@ export const Link = Mark.create<LinkOptions>({
},

parseHTML() {
return [{ tag: 'a[href]:not([href *= "javascript:" i])' }]
return [{
tag: 'a[href]',
getAttrs: dom => {
const href = (dom as HTMLElement).getAttribute('href')

// prevent XSS attacks
if (!href || !isAllowedUri(href)) {
return false
}
return { href }
},
}]
},

renderHTML({ HTMLAttributes }) {
// prevent XSS attacks
if (!isAllowedUri(HTMLAttributes.href)) {
// strip out the href
return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]
Expand Down
54 changes: 50 additions & 4 deletions tests/cypress/integration/extensions/link.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ describe('extension-link', () => {
'ftp://info@example.com',
]

validUrls.forEach(url => {
it('does output href tag for valid schemas', () => {
it('does output href tag for valid JSON schemas', () => {
validUrls.forEach(url => {
editor = new Editor({
element: createEditorEl(),
extensions: [
Expand Down Expand Up @@ -64,6 +64,28 @@ describe('extension-link', () => {
})

expect(editor.getHTML()).to.include(url)
expect(JSON.stringify(editor.getJSON())).to.include(url)

editor?.destroy()
getEditorEl()?.remove()
})
})

it('does output href tag for valid HTML schemas', () => {
validUrls.forEach(url => {
editor = new Editor({
element: createEditorEl(),
extensions: [
Document,
Text,
Paragraph,
Link,
],
content: `<p><a href="${url}">hello world!</a></p>`,
})

expect(editor.getHTML()).to.include(url)
expect(JSON.stringify(editor.getJSON())).to.include(url)

editor?.destroy()
getEditorEl()?.remove()
Expand Down Expand Up @@ -164,8 +186,8 @@ describe('extension-link', () => {
'javascript\x0d:alert(window.origin)',
]

invalidUrls.forEach(url => {
it('does not output src tag for javascript schema', () => {
it('does not output href for :javascript links in JSON schema', () => {
invalidUrls.forEach(url => {
editor = new Editor({
element: createEditorEl(),
extensions: [
Expand Down Expand Up @@ -199,6 +221,30 @@ describe('extension-link', () => {
})

expect(editor.getHTML()).to.not.include(url)
// Unfortunately, if the content is provided as JSON, it stays in the editor instance until it's destroyed
// At least, it cannot be outputted as HTML into a page
// expect(JSON.stringify(editor.getJSON())).to.not.include(url)

editor?.destroy()
getEditorEl()?.remove()
})
})

it('does not output href for :javascript links in HTML schema', () => {
invalidUrls.forEach(url => {
editor = new Editor({
element: createEditorEl(),
extensions: [
Document,
Text,
Paragraph,
Link,
],
content: `<p><a href="${url}">hello world!</a></p>`,
})

expect(editor.getHTML()).to.not.include(url)
expect(JSON.stringify(editor.getJSON())).to.not.include(url)

editor?.destroy()
getEditorEl()?.remove()
Expand Down

0 comments on commit 738c436

Please sign in to comment.