Skip to content

Stored HTML injection in BOM validation results via unescaped Part name

Moderate
jbtronics published GHSA-qqrh-jjhg-vv5r Jun 24, 2026

Package

composer part-db/part-db-server (Composer)

Affected versions

<= 2.12.1

Patched versions

2.12.2+

Description

Stored HTML Injection in BOM Validation Results via Unescaped Part Name

Summary

Part-DB renders BOM validation information messages using Twig's |raw filter. These messages include translated placeholders populated with user-controlled Part names.

A user who can edit a Part name can store HTML markup in the Part name. When another user imports a BOM CSV referencing that Part ID, the malicious Part name is rendered as HTML in the victim's BOM validation result page.

This results in a cross-user stored HTML injection issue. JavaScript execution appears to be blocked by the current Content Security Policy, but arbitrary HTML links, forms, images, and CSS-based UI elements can still be injected into a trusted Part-DB page.

Affected Version

Tested on Part-DB version 2.12.1 using the official Docker image.

1

Affected Components

Relevant code paths identified during review:

  • src/Services/ImportExportSystem/BOMValidationService.php
  • templates/projects/_bom_validation_results.html.twig
  • templates/projects/import_bom_map_fields.html.twig
  • translations/messages.en.xlf

The vulnerable rendering sink is the BOM validation result template, where information messages are rendered using {{ info|raw }}.

The Part name is inserted into the translated partdb_link_success message and then rendered as raw HTML.

Impact

This is a cross-user stored HTML injection issue.

The attacker needs permission to create or edit a Part name. The victim needs permission to import a BOM into a Project.

The issue was reproduced with two non-admin users using the Editor permission preset:

  • Attacker user: creates/edits a Part name containing HTML markup.
  • Victim user: imports a BOM CSV referencing the attacker's Part ID.
  • Result: the attacker's HTML is rendered in the victim's BOM validation result page.

The current CSP appears to block inline JavaScript execution, such as <script> tags and inline event handlers. However, the injection still allows arbitrary HTML to be rendered inside the victim's trusted Part-DB page, including links, forms, tracking images, and CSS-based UI redressing/phishing overlays.

Proof of Concept

Step 1: Attacker creates a malicious Part name

Log in as a non-admin user with the Editor preset and create or edit a Part.

Set the Part name to the following payload:

<a href=//attacker.example style=color:red;font-size:20px>Re-authenticate</a>

In the test environment, this Part was saved with ID 2.

6

Step 2: Victim imports a BOM CSV referencing the malicious Part

Log in as a different non-admin user with the Editor preset.

Create a Project and import the following BOM CSV as Generic CSV:

Part-DB ID,Designator,Quantity
2,R1,1
,R2,2

Map the CSV columns as follows:

Part-DB ID  -> Part-DB ID
Designator  -> Designator
Quantity    -> Quantity

The second row intentionally contains an invalid quantity/designator combination. This forces the BOM validation page to render the validation result object. The issue is demonstrated in the Information section, where the Part name from line 1 is rendered as HTML.

Step 3: Observe the injected HTML in the victim's validation result page

After clicking Preview, the validation result page displays:

Line 1: Successfully linked to Part-DB part "Re-authenticate" (ID: 2).

However, Re-authenticate is not rendered as plain text. It is rendered as a red HTML link controlled by the attacker.

7

Expected Behavior

User-controlled Part names should be escaped before being rendered in BOM validation messages.

The payload should be displayed as plain text, for example:

&lt;a href=//attacker.example style=color:red;font-size:20px&gt;Re-authenticate&lt;/a&gt;

Actual Behavior

The Part name is inserted into the translated validation message and rendered through {{ info|raw }}, causing attacker-controlled HTML to be interpreted by the browser.

Why this is security-relevant

This is not an administrative feature or an intended rich-text field. The malicious content is stored in a normal Part name field and later rendered in another user's BOM validation result page.

The victim does not need to edit or directly view the malicious Part. The payload is triggered when the victim imports a BOM CSV referencing the Part ID.

This crosses a user boundary because one user controls the stored Part name and another user renders it during BOM validation.

Suggested Fix

Avoid rendering BOM validation information messages with |raw unless all placeholders are safely escaped.

For example, change the template rendering from:

<li>{{ info|raw }}</li>

to:

<li>{{ info }}</li>

or:

<li>{{ info|e }}</li>

If some validation messages intentionally contain trusted HTML, then user-controlled placeholders should be escaped before interpolation. For example:

'%name%' => htmlspecialchars($existing_part->getName(), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')

The same pattern should be reviewed for other BOM validation placeholders, including CSV-controlled values such as designators, package fields, and quantities.

Notes

JavaScript execution was not required to demonstrate the issue. The current CSP appears to block inline JavaScript execution, but arbitrary HTML injection still occurs and can be used for phishing, UI redressing, external links, injected forms, or tracking images inside a trusted Part-DB page.

The issue was reproduced on Part-DB 2.12.1 with two non-admin users using the Editor permission preset.

Severity

Moderate

CVE ID

CVE-2026-55600

Weaknesses

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users. Learn more on MITRE.

Credits