Skip to content

Commit b78c9da

Browse files
committed
fix: sre vulnerability issue fixed
1 parent 4716bf9 commit b78c9da

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

src/helper/sanitize.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
type AllowedTags = 'p' | 'a' | 'strong' | 'em' | 'ul' | 'ol' | 'li';
3+
type AllowedAttributes = 'href' | 'title' | 'target' | 'alt' | 'src';
4+
5+
export function sanitizeHTML(input: string, allowedTags: AllowedTags[] = ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li'], allowedAttributes: AllowedAttributes[] = ['href', 'title', 'target']): string {
6+
// Regular expression to find and remove all HTML tags except the allowed ones
7+
const sanitized = input.replace(/<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi, (match, tag) => {
8+
return allowedTags.includes(tag.toLowerCase()) ? match : '';
9+
});
10+
11+
// Regular expression to remove all attributes except the allowed ones
12+
const cleaned = sanitized.replace(/\s([a-z:]+)=['"][^'"]*['"]/gi, (match, attribute) => {
13+
return allowedAttributes.includes(attribute.toLowerCase()) ? match : '';
14+
});
15+
16+
return cleaned;
17+
}
18+

src/options/default-node-options.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Next, RenderOption } from ".";
22
import MarkType from "../nodes/mark-type";
33
import Node from "../nodes/node";
44
import NodeType from "../nodes/node-type";
5+
import { sanitizeHTML } from "../helper/sanitize";
56

67
export const defaultNodeOption: RenderOption = {
78
[NodeType.DOCUMENT]:(node: Node) => {
@@ -11,16 +12,19 @@ export const defaultNodeOption: RenderOption = {
1112
return `<p${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``}>${next(node.children)}</p>`
1213
},
1314
[NodeType.LINK]:(node: Node, next: Next) => {
15+
const sanitizedHref = sanitizeHTML(node.attrs.href || node.attrs.url);
1416
if (node.attrs.target) {
15-
return `<a${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} href="${node.attrs.href || node.attrs.url}" target="${node.attrs.target}">${next(node.children)}</a>`
17+
return `<a${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} href="${sanitizedHref}" target="${node.attrs.target}">${next(node.children)}</a>`
1618
}
17-
return `<a${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} href="${node.attrs.href || node.attrs.url}">${next(node.children)}</a>`
19+
return `<a${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} href="${sanitizedHref}">${next(node.children)}</a>`
1820
},
1921
[NodeType.IMAGE]:(node: Node, next: Next) => {
20-
return `<img${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} src="${node.attrs.src || node.attrs.url}" />${next(node.children)}`
22+
const sanitizedSrc = sanitizeHTML(node.attrs.src || node.attrs.url);
23+
return `<img${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} src="${sanitizedSrc}" />${next(node.children)}`
2124
},
2225
[NodeType.EMBED]:(node: Node, next: Next) => {
23-
return `<iframe${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} src="${node.attrs.src || node.attrs.url}">${next(node.children)}</iframe>`
26+
const sanitizedSrc = sanitizeHTML(node.attrs.src || node.attrs.url);
27+
return `<iframe${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``} src="${sanitizedSrc}">${next(node.children)}</iframe>`
2428
},
2529
[NodeType.HEADING_1]:(node: Node, next: Next) => {
2630
return `<h1${node.attrs.style ? ` style="${node.attrs.style}"` : ``}${node.attrs['class-name'] ? ` class="${node.attrs['class-name']}"` : ``}${node.attrs.id ? ` id="${node.attrs.id}"` : ``}>${next(node.children)}</h1>`

src/options/default-options.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,32 @@ import { RenderOption } from '.';
33
import { Metadata } from '../Models/metadata-model';
44
import { EmbeddedItem } from '../Models/embedded-object';
55
import { EntryNode } from '../Models/json-rte-model';
6+
import { sanitizeHTML } from '../helper/sanitize'
67

78
export const defaultOptions: RenderOption = {
8-
[StyleType.BLOCK]: (item: EmbeddedItem | EntryNode) =>
9-
`<div><p>${item.title || item.uid}</p><p>Content type: <span>${item._content_type_uid || (item.system ? item.system.content_type_uid : '')}</span></p></div>`,
10-
[StyleType.INLINE]: (item: EmbeddedItem | EntryNode) => `<span>${item.title || item.uid}</span>`,
11-
[StyleType.LINK]: (item: EmbeddedItem | EntryNode, metadata: Metadata) => `<a href="${item.url}">${metadata.text || item.title || item.uid || (item.system ? item.system.uid : '')}</a>`,
12-
[StyleType.DISPLAY]: (item: EmbeddedItem | EntryNode, metadata: Metadata) => `<img src="${item.url}" alt="${metadata.attributes.alt || item.title || item.filename || item.uid
13-
|| (item.system ? item.system.uid : '')}" />`,
14-
[StyleType.DOWNLOAD]: (item: EmbeddedItem | EntryNode, metadata: Metadata) => `<a href="${item.url}">${metadata.text || item.title || item.uid || (item.system ? item.system.content_type_uid : '')}</a>`,
9+
[StyleType.BLOCK]: (item: EmbeddedItem | EntryNode) => {
10+
const title = sanitizeHTML(item.title || item.uid);
11+
const content_type_uid = sanitizeHTML(item._content_type_uid || (item.system ? item.system.content_type_uid : ''));
12+
return `<div><p>${title}</p><p>Content type: <span>${content_type_uid}</span></p></div>`;
13+
},
14+
[StyleType.INLINE]: (item: EmbeddedItem | EntryNode) => {
15+
const title = sanitizeHTML(item.title || item.uid);
16+
return `<span>${title}</span>`;
17+
},
18+
[StyleType.LINK]: (item: EmbeddedItem | EntryNode, metadata: Metadata) => {
19+
const url = sanitizeHTML(item.url || 'undefined');
20+
const text = sanitizeHTML(metadata.text || item.title || item.uid || (item.system ? item.system.uid : ''));
21+
return `<a href="${url}">${text}</a>`;
22+
},
23+
[StyleType.DISPLAY]: (item: EmbeddedItem | EntryNode, metadata: Metadata) => {
24+
const url = sanitizeHTML(item.url || 'undefined');
25+
const alt = sanitizeHTML(metadata.attributes.alt || item.title || item.filename || item.uid
26+
|| (item.system ? item.system.uid : ''));
27+
return `<img src="${url}" alt="${alt}" />`;
28+
},
29+
[StyleType.DOWNLOAD]: (item: EmbeddedItem | EntryNode, metadata: Metadata) => {
30+
const href = sanitizeHTML(item.url || 'undefined');
31+
const text = sanitizeHTML(metadata.text || item.title || item.uid || (item.system ? item.system.content_type_uid : ''));
32+
return `<a href="${href}">${text}</a>`;
33+
},
1534
};

0 commit comments

Comments
 (0)