Skip to content

fix(website): escape vulnerability IDs in hierarchy display#5228

Merged
michaelkedar merged 2 commits intogoogle:masterfrom
TristanInSec:escape-hierarchy-ids
Apr 13, 2026
Merged

fix(website): escape vulnerability IDs in hierarchy display#5228
michaelkedar merged 2 commits intogoogle:masterfrom
TristanInSec:escape-hierarchy-ids

Conversation

@TristanInSec
Copy link
Copy Markdown
Contributor

Summary

construct_hierarchy_string() in gcp/website/frontend_handlers.py builds the upstream/downstream hierarchy HTML for vulnerability pages by concatenating raw vuln_id strings into <li> and <a href=...> fragments. The resulting string is rendered with Jinja2's | safe filter in vulnerability.html, so any markup characters that reach this code path are emitted verbatim.

This PR wraps each id with markupsafe.escape and assembles the output as markupsafe.Markup, so ids drawn from source records are always HTML-escaped in the rendered hierarchy — matching how the rest of the template handles data-derived text.

Changes

  • gcp/website/frontend_handlers.pyconstruct_hierarchy_string now returns Markup; each vuln_id is passed through escape() before being spliced into the <li> / <a> fragments, using Markup(...).format(...) so nested Markup fragments compose safely.
  • gcp/website/frontend_handlers_test.py — new ConstructHierarchyStringTest with three cases:
    • a known id containing <script> — verified not present verbatim, present as &lt;script&gt;
    • an unknown id containing "><img ...> — verified escaped
    • a plain CVE-2024-0001 — verified the anchor still renders identically to before

Testing

  • python3 -m unittest frontend_handlers_test.ConstructHierarchyStringTest — passes locally against the patched function.
  • Existing hierarchy rendering is byte-identical for ids containing only [A-Za-z0-9:._-], so no change is expected for any well-formed OSV id.

construct_hierarchy_string() in gcp/website/frontend_handlers.py builds
the upstream/downstream hierarchy HTML for vulnerability pages by
concatenating raw vuln_id strings into <li> and <a href=...> fragments.
The result is rendered with Jinja2's |safe filter, so any non-ASCII
markup characters that reach this code path would be emitted verbatim.

Wrap each id with markupsafe.escape and assemble the output as
markupsafe.Markup so that ids drawn from source records are always
HTML-escaped in the rendered hierarchy, matching how the rest of the
template handles data-derived text.

Adds unit tests in frontend_handlers_test.py covering the known-id,
unknown-id, and plain-id code paths.
@michaelkedar
Copy link
Copy Markdown
Member

/gcbrun

Copy link
Copy Markdown
Member

@michaelkedar michaelkedar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@michaelkedar michaelkedar merged commit fb9be92 into google:master Apr 13, 2026
21 checks passed
tymzd pushed a commit to tymzd/osv.dev that referenced this pull request Apr 13, 2026
)

## Summary

`construct_hierarchy_string()` in `gcp/website/frontend_handlers.py`
builds the upstream/downstream hierarchy HTML for vulnerability pages by
concatenating raw `vuln_id` strings into `<li>` and `<a href=...>`
fragments. The resulting string is rendered with Jinja2's `| safe`
filter in `vulnerability.html`, so any markup characters that reach this
code path are emitted verbatim.

This PR wraps each id with `markupsafe.escape` and assembles the output
as `markupsafe.Markup`, so ids drawn from source records are always
HTML-escaped in the rendered hierarchy — matching how the rest of the
template handles data-derived text.

## Changes

- `gcp/website/frontend_handlers.py` — `construct_hierarchy_string` now
returns `Markup`; each `vuln_id` is passed through `escape()` before
being spliced into the `<li>` / `<a>` fragments, using
`Markup(...).format(...)` so nested `Markup` fragments compose safely.
- `gcp/website/frontend_handlers_test.py` — new
`ConstructHierarchyStringTest` with three cases:
- a known id containing `<script>` — verified not present verbatim,
present as `&lt;script&gt;`
  - an unknown id containing `"><img ...>` — verified escaped
- a plain `CVE-2024-0001` — verified the anchor still renders
identically to before

## Testing

- `python3 -m unittest
frontend_handlers_test.ConstructHierarchyStringTest` — passes locally
against the patched function.
- Existing hierarchy rendering is byte-identical for ids containing only
`[A-Za-z0-9:._-]`, so no change is expected for any well-formed OSV id.

---------

Co-authored-by: TristanInSec <tristan.mtn@gmail.com>
@TristanInSec
Copy link
Copy Markdown
Contributor Author

PS: This PR fixes the issue reported in https://issuetracker.google.com/issues/502293433

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants