Skip to content

Commit 08145a0

Browse files
committed
chore: use sanitize-html at endpoint
1 parent 38596e2 commit 08145a0

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

server/api/contributors.get.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import sanitize from 'sanitize-html'
2+
13
export type Role = 'steward' | 'maintainer' | 'contributor'
24

35
export interface GitHubUserData {
@@ -40,6 +42,24 @@ const DEFAULT_USER_INFO: GitHubUserData = {
4042
twitterUsername: null,
4143
}
4244

45+
// Configure sanitize-html for GitHub's companyHTML and company fields
46+
const SANITIZE_HTML_OPTIONS: sanitize.IOptions = {
47+
allowedTags: ['a', 'span', 'strong', 'em', 'code'],
48+
allowedAttributes: {
49+
a: ['href', 'target', 'rel'],
50+
},
51+
transformTags: {
52+
a: (tagName, attribs) => ({
53+
tagName,
54+
attribs: {
55+
...attribs,
56+
target: '_blank',
57+
rel: 'noopener noreferrer',
58+
},
59+
}),
60+
},
61+
}
62+
4363
interface TeamMembers {
4464
steward: Set<string>
4565
maintainer: Set<string>
@@ -85,22 +105,14 @@ async function fetchTeamMembers(token: string): Promise<TeamMembers | null> {
85105
}
86106

87107
/**
88-
* Cleans GitHub HTML to remove tracking data and add security attributes.
89-
* Specifically targets data-octo, data-hovercard, and keyboard shortcuts.
108+
* Sanitizes GitHub HTML to remove XSS vectors while preserving safe formatting.
109+
* Applies to both rich companyHTML and plain-text company fields.
90110
*/
91111
function sanitizeGitHubHTML(html: string | null): string | null {
92112
if (!html) return null
93113

94-
return (
95-
html
96-
// 1. Remove GitHub-specific tracking and metadata attributes
97-
.replace(/\s(data-hovercard-[a-z-]+|data-octo-[a-z-]+|aria-keyshortcuts)="[^"]*"/gi, '')
98-
// 2. Inject security and target attributes to all <a> tags
99-
.replace(/<a /gi, '<a target="_blank" rel="noopener noreferrer" ')
100-
// 3. Clean up any resulting double spaces
101-
.replace(/\s{2,}/g, ' ')
102-
.trim()
103-
)
114+
const cleaned = sanitize(html.trim(), SANITIZE_HTML_OPTIONS)
115+
return cleaned === '' ? null : cleaned
104116
}
105117

106118
/**

0 commit comments

Comments
 (0)