# Unescaped CI values in rendered output

CI job names, namespaces, or config values reaching html_safe or template output without escaping

_Area: Software supply chain and CI/CD. Seen in 2 disclosed reports; one confirmed bounty: $3,000; latest 2021-01-08. Updated 2026-10-23._

## How it works
CI configuration and job metadata are treated as trusted display data. A value the user controls (job name, kubernetes namespace, a diagram directive) is interpolated into a rendered page or template, and the render path either marks it `html_safe` or skips escaping. The assumption that breaks: that CI fields are safe to render as HTML because they come from the project's own config. Anyone who can set that config, or whose job name appears in an error, controls markup shown to other users.

## Where it shows up
- Serializers/entities marking `failure_message` or similar fields `html_safe` [E2](https://bugbountylibrary.com/r/h1%3A950190.md)
- Error messages that echo job or dependency names back to the viewer [E2](https://bugbountylibrary.com/r/h1%3A950190.md)
- Vue templates binding CI YAML fields (`%{kubernetesNamespace}`, environment url/name) without escaping [E3](https://bugbountylibrary.com/r/h1%3A856554.md)
- Renderers whose sanitizer guard and render guard disagree on a flag's type (strict `=== false` vs truthy string `"false"`) [E1](https://bugbountylibrary.com/r/h1%3A1212822.md)
- Init/directive config that can flip a rendering option after the security level is set [E1](https://bugbountylibrary.com/r/h1%3A1212822.md)

## How to review
Trace every user-controlled CI value to its output sink. The invariant: any value originating from CI config or job metadata must be escaped at render time, or the sink must be a context that cannot execute markup. Check that sanitization decisions and render decisions use the same comparison on the same type; a flag checked strictly in one place and truthily in another is a bypass. Confirm security-level settings cannot be overridden by in-content directives. Grep for `html_safe`, `raw`, `v-html`, and template interpolation of CI fields.

## Variants seen
- Stored XSS via job name in a `html_safe` dependency error message [E2](https://bugbountylibrary.com/r/h1%3A950190.md)
- Stored XSS via kubernetes namespace in a Vue job-page template [E3](https://bugbountylibrary.com/r/h1%3A856554.md)
- Sanitizer bypass via type confusion on a diagram label flag, also enabling CSP bypass through artifacts [E1](https://bugbountylibrary.com/r/h1%3A1212822.md)

## Impact and severity
Stored XSS executing in other users' browsers on the CI/job pages, with account takeover as the stated outcome [E1](https://bugbountylibrary.com/r/h1%3A1212822.md)[E2](https://bugbountylibrary.com/r/h1%3A950190.md)[E3](https://bugbountylibrary.com/r/h1%3A856554.md). Severity rises when the payload persists in shared views (job pages, artifacts) and when it also defeats CSP [E1](https://bugbountylibrary.com/r/h1%3A1212822.md). Default-on features widen exposure [E2](https://bugbountylibrary.com/r/h1%3A950190.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1212822.md
- E2: https://bugbountylibrary.com/r/h1%3A950190.md
- E3: https://bugbountylibrary.com/r/h1%3A856554.md
