Escape profile badge custom labels#4865
Conversation
saim256
left a comment
There was a problem hiding this comment.
Approving current head e217036.
The #4815 badge-label injection path is addressed in the scoped areas: the Shields label segment is URL-encoded with safe='', generated HTML attributes are escaped with quote handling, Markdown alt text escapes bracket/control characters, and the browser preview no longer assigns the returned preview_html through innerHTML. The regression tests cover the quote/script/slash payload and the DOM preview path.
Validation performed:
python -m pytest tests\test_profile_badge_generator_security.py -q-> 2 passedpython -m py_compile profile_badge_generator.py tests\test_profile_badge_generator_security.py-> passedpython tools\bcos_spdx_check.py --base-ref origin/main-> BCOS SPDX check: OKgit diff --check origin/main...HEAD -- profile_badge_generator.py tests/test_profile_badge_generator_security.py-> passedpython -m ruff check profile_badge_generator.py tests\test_profile_badge_generator_security.py --select E9,F821,F811 --output-format=concise-> All checks passed
Scope note: profile_badge_generator.py still has an existing app.run(debug=True) dev entrypoint, but that is not introduced by this PR and is already being handled under the separate Flask debug issue/PR track.
jaxint
left a comment
There was a problem hiding this comment.
LGTM! Thanks for contributing. Approved.
jaxint
left a comment
There was a problem hiding this comment.
LGTM! Thanks for contributing. Approved.
godd-ctrl
left a comment
There was a problem hiding this comment.
Approved current head e217036.
The profile badge fix escapes the generated HTML/preview markup, avoids assigning returned preview_html through innerHTML, percent-encodes the shield label path segment, and keeps generated Markdown alt text from breaking out of the image syntax. The added regression tests cover the custom-message injection path and DOM preview behavior.
Validation performed:
- git diff --name-status origin/main...HEAD -> profile_badge_generator.py modified, tests/test_profile_badge_generator_security.py added
- git diff --check origin/main...HEAD -> passed
- python tools\bcos_spdx_check.py --base-ref origin/main -> passed
- python -m py_compile profile_badge_generator.py tests\test_profile_badge_generator_security.py -> passed
- python -m pytest tests\test_profile_badge_generator_security.py -q -> 2 passed
- Additional local smoke with hostile labels including quote/onerror, script tag, newline, and URL punctuation -> passed
No blocking issues found in the reviewed diff.
jaxint
left a comment
There was a problem hiding this comment.
LGTM! Thanks for contributing. Approved.
Code Review: Escape profile badge custom labelsSummaryThis PR fixes an HTML injection vulnerability in the BCOS badge generator. User-controlled input (custom_message, username) was being directly interpolated into HTML without escaping, allowing XSS attacks. Positive Observations ✅
Issues Found 🔍1.
|
jaxint
left a comment
There was a problem hiding this comment.
Great contribution! LGTM.
loganoe
left a comment
There was a problem hiding this comment.
Security review for Scottcjn/rustchain-bounties#73 on current head e217036f3a6c8b45aa838ef48c6f649ac7c73163.
The badge-label injection fix covers the relevant output contexts: the Shields label path segment is percent-encoded with safe='', generated HTML attributes are escaped with quote handling, Markdown alt text no longer keeps bracket/control breakouts, and the preview JavaScript now creates an image node instead of assigning API-provided markup through innerHTML.
Validation performed:
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-project --with pytest --with flask python -m pytest tests/test_profile_badge_generator_security.py -q-> 2 passedpython3 -m py_compile profile_badge_generator.py tests/test_profile_badge_generator_security.py-> passedgit diff --check origin/main...HEAD -- profile_badge_generator.py tests/test_profile_badge_generator_security.py-> passedpython3 tools/bcos_spdx_check.py --base-ref origin/main-> OK- Hostile-label API smoke with quote/onerror/script/slash payload confirmed the badge URL is percent-encoded and preview HTML uses escaped attributes rather than raw injected markup.
No blocking issues found in this diff.
508704820
left a comment
There was a problem hiding this comment.
Code Review: Escape Profile Badge Custom Labels
Summary
Fixes XSS vulnerability in the profile badge generator. Previously used innerHTML with unsanitized data; now uses DOM manipulation (replaceChildren + createElement) and server-side HTML escaping via html.escape().
What Works Well
- XSS fix: innerHTML with user data → safe DOM manipulation
- Server-side escaping: html_utils.escape() on custom_label
- DOM API: replaceChildren() + createElement('img') instead of innerHTML
- Defense in depth: Both client-side and server-side sanitization
Issues Found
1. Low — alt_text not escaped server-side
data.alt_text || 'RustChain Badge' is used directly. If alt_text contains special characters, it could cause issues. Consider escaping on the server side.
2. Nit — html_utils import name
import html as html_utils — standard library, but the alias is unusual. import html is more conventional since Python 3.
Verdict: Approve
Important XSS fix. Defense-in-depth approach with both client and server sanitization.
Summary
safe=""so custom labels cannot alter the badge URL path.innerHTMLsink with DOM-created image nodes while keepingpreview_htmlsafe for existing API consumers.Fixes #4815.
Validation
python -m pytest tests\test_profile_badge_generator_security.py -q-> 2 passedpython -m py_compile profile_badge_generator.py tests\test_profile_badge_generator_security.py-> passedgit diff --check -- profile_badge_generator.py tests\test_profile_badge_generator_security.py-> passedpython tools\bcos_spdx_check.py --base-ref origin/main-> OKpython -m ruff check profile_badge_generator.py tests\test_profile_badge_generator_security.py --select E9,F821,F811 --output-format=concise-> unavailable locally:No module named ruff