Skip to content

Commit e51659d

Browse files
HeyItsGilbertclaude
andcommitted
Fix YAML frontmatter injection in event submission workflow
Replace hand-rolled f-string YAML serialization with yaml.safe_dump() to prevent frontmatter injection via unescaped quotes in issue body fields. Strip raw HTML from event descriptions to block stored XSS through goldmark's unsafe renderer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ee1ab24 commit e51659d

1 file changed

Lines changed: 16 additions & 15 deletions

File tree

.github/workflows/add-event.yml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
ISSUE_TITLE: ${{ github.event.issue.title }}
2727
run: |
2828
python3 - <<'PYEOF'
29-
import os, re
29+
import os, re, yaml
3030
3131
body = os.environ['ISSUE_BODY']
3232
issue_num = os.environ['ISSUE_NUMBER']
@@ -46,25 +46,26 @@ jobs:
4646
virtual_s = field('Is this a virtual event?')
4747
description = field('Event Description')
4848
49-
virtual = 'true' if virtual_s.startswith(('Yes', 'Hybrid')) else 'false'
49+
virtual = virtual_s.startswith(('Yes', 'Hybrid'))
5050
5151
# Generate a URL-safe slug: name + year
5252
slug = re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-')
5353
slug = f"{slug}-{start_date[:4]}"
5454
55-
end_line = f'\nendDate: "{end_date}"' if end_date else ''
56-
content = f"""---
57-
title: "{name}"
58-
startDate: "{start_date}"{end_line}
59-
where: "{location}"
60-
externalUrl: "{url}"
61-
virtual: {virtual}
62-
---
63-
{description}
64-
"""
65-
# Dedent (the heredoc indents every line)
66-
import textwrap
67-
content = textwrap.dedent(content)
55+
# Strip raw HTML from description to prevent stored XSS via goldmark unsafe mode
56+
description = re.sub(r'<[^>]+>', '', description)
57+
58+
fm = {
59+
'title': name,
60+
'startDate': start_date,
61+
'where': location,
62+
'externalUrl': url,
63+
'virtual': virtual,
64+
}
65+
if end_date:
66+
fm['endDate'] = end_date
67+
68+
content = '---\n' + yaml.safe_dump(fm, default_flow_style=False, allow_unicode=True) + '---\n' + description + '\n'
6869
6970
filepath = f'content/calendar/{slug}.md'
7071
os.makedirs('content/calendar', exist_ok=True)

0 commit comments

Comments
 (0)