Skip to content

Commit 5272ca8

Browse files
authored
Remove rel and target from outgoing links (#891)
<!-- Please read https://github.com/SableClient/Sable/blob/dev/CONTRIBUTING.md before submitting your pull request --> ### Description <!-- Please include a summary of the change. Please also include relevant motivation and context. List any dependencies that are required for this change. --> Removes rel and target attributes from outgoing links #### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings ### AI disclosure: - [ ] Partially AI assisted (clarify which code was AI assisted and briefly explain what it does). - [ ] Fully AI generated (explain what all the generated code does in moderate detail). <!-- Write any explanation required here, but do not generate the explanation using AI!! You must prove you understand what the code in this PR does. -->
2 parents f35dcee + 66fe404 commit 5272ca8

6 files changed

Lines changed: 12 additions & 12 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
default: patch
3+
---
4+
5+
Remove target and rel attributes from outgoing html links.

src/app/components/editor/output.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const elementToCustomHtml = (
8282
case BlockType.Link:
8383
return testMatrixTo(node.href)
8484
? sanitizeText(node.href)
85-
: `<a href="${encodeURI(node.href)}" target="_blank" rel="noreferrer noopener">${children}</a>`;
85+
: `<a href="${encodeURI(node.href)}">${children}</a>`;
8686
case BlockType.Command:
8787
return `/${sanitizeText(node.command)}`;
8888
default:

src/app/plugins/markdown/markdownToHtml.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ describe('markdownToHtml', () => {
3535
it('converts links', () => {
3636
const result = markdownToHtml('[link](https://example.com)');
3737
expect(result).toContain('<a href="https://example.com"');
38+
expect(result).not.toContain('target=');
39+
expect(result).not.toContain('rel=');
3840
});
3941

4042
it('converts spoiler syntax', () => {

src/app/plugins/markdown/markdownToHtml.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,8 @@ export function markdownToHtml(markdown: string, options?: MarkdownToHtmlOptions
154154

155155
const allowlistedHtml = escapeNonAllowlistedHtmlTags(unescapedInline);
156156

157-
// Force all links to open in a new tab, validate <ol start>.
157+
// Validate <ol start> after sanitization.
158158
DOMPurify.addHook('afterSanitizeAttributes', (node) => {
159-
if (node.tagName === 'A' && node.getAttribute('href')) {
160-
node.setAttribute('target', '_blank');
161-
node.setAttribute('rel', 'noreferrer noopener');
162-
}
163159
if (node.tagName === 'OL') {
164160
const start = node.getAttribute('start');
165161
if (start !== null && !ORDERED_LIST_START_REGEX.test(start)) {
@@ -177,8 +173,6 @@ export function markdownToHtml(markdown: string, options?: MarkdownToHtmlOptions
177173
'title',
178174
'height',
179175
'width',
180-
'target',
181-
'rel',
182176
'data-mx-emoticon',
183177
'data-mx-spoiler',
184178
'data-mx-maths',
@@ -194,9 +188,8 @@ export function markdownToHtml(markdown: string, options?: MarkdownToHtmlOptions
194188
// Ensure these safe attrs survive sanitization even when the input HTML
195189
// originates from markdown-embedded tags (e.g. custom emoji <img>).
196190
// `start` must be URI-safe or DOMPurify drops it when ALLOWED_URI_REGEXP is set.
197-
ADD_ATTR: ['target', 'rel', 'height', 'width'],
191+
ADD_ATTR: ['height', 'width'],
198192
ADD_URI_SAFE_ATTR: ['start'],
199-
// Force all links to have safe rel attribute
200193
FORCE_BODY: false,
201194
ALLOWED_URI_REGEXP: /^(?:https?|ftp|mailto|magnet|mxc):/i,
202195
});

src/app/utils/sanitize.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ describe('sanitizeCustomHtml', () => {
5353
expect(result).toContain('data-mx-maths="x"');
5454
expect(result).toContain('data-md="**"');
5555
expect(result).toContain('href="https://example.com"');
56-
expect(result).toContain('target="_blank"');
5756
expect(result).toContain('data-md="[]()"');
57+
expect(result).not.toContain('target=');
5858
expect(result).not.toContain('rel=');
5959
expect(result).toContain('<ol start="2" data-md="1.">');
6060
expect(result).not.toContain('type=');

src/app/utils/sanitize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const permittedHtmlTags = [
4646

4747
const permittedTagToAttributes = {
4848
span: ['data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'data-mx-maths', 'data-md'],
49-
a: ['target', 'href', 'data-md'],
49+
a: ['href', 'data-md'],
5050
img: ['width', 'height', 'alt', 'title', 'src', 'data-mx-emoticon'], // data-mx-emoticon is for MSC2545
5151
ol: ['start', 'data-md'],
5252
ul: ['data-md'],

0 commit comments

Comments
 (0)