Pyddock MCP Server

pyddock PyPI v0.4.2

Published by portablestew — no publish provenance, so origin is unverified, but the source is public: the repository link below is self-declared yet readable, so you can inspect the code before adopting it.

MCP server that gives AI agents pre-approved Python, shell, and file I/O tools with declarative policy controls

Trust grade
D
60/100
Last scanned get badge →
Trust
D · 60/100
Adoption risk for you: the threat score, then adjusted down for blast radius, publisher verification and how much the scan could see. Deterministic; every point is auditable.
Capability
High
Blast radius if it went rogue — what the server’s tools could reach. Independent of trust.
Coverage
Source
How much the scan could actually inspect. Shallow coverage is stated, never hidden.
Share this Trust Score
𝕏 Share LinkedIn Reddit
D Why this grade threat 67 − adoption risk = 60/100

The grade answers one question — how safe is this server for you to adopt — so it is computed in two auditable stages. Nothing below is an opinion or an LLM's guess; every line is a real term the deterministic engine applied, and the same input always yields the same number.

1. Threat score — 100 − 33.3 = 67. What the published surface and source actually contain:

PointsWhat was foundCategory
−33.3 Hardcoded PEM private key in server code ×3 MTC-SRC-008 exfiltration

2. Client adoption risk — 67 − 7 = 60. Three small, subtract-only factors that reflect your risk in adopting it — a clean scan proves less on a powerful, unverified or barely-inspectable package, so the grade says so plainly:

PointsAdoption-risk factor
−6 capability blast radius (high) — client exposure if the model is manipulated
−1 publisher verification (public source) — no provenance, but the source is public and inspectable

Grade capped: 2 confirmed high findings → grade capped at D. A hard gate overrides the point total — no amount of clean surface buys back a confirmed catastrophe.

Capability observations and info notes are shown under Findings but never scored. Open any row's finding below for the file, line and evidence behind a deduction.

Findings 20

high Sensitive-source and external-sink co-existMTC-FLOW-004

Tools that read sensitive data ([fs_readfile]) and tools that can send data out ([run_shell]) are exposed together. An agent can move private data to the sink.

Evidence: sources [fs_readfile] → sinks [run_shell]

Fix: Keep secret-reading and egress capabilities on separate, separately-approved servers.

Location: flow fs_readfile → run_shell

high Hardcoded PEM private key in server code (.trunk/plugins/trunk/linters/trivy/test_data/secrets.py)MTC-SRC-008

A hardcoded PEM private key (a live-looking credential hardcoded in shipped code) appears in `.trunk/plugins/trunk/linters/trivy/test_data/secrets.py:11`. Secrets in source ship to everyone who installs the package and are a direct credential leak.

Evidence: PEM private key: ----…(redacted)

Fix: Remove the secret, rotate it, and load credentials from the environment or a secret store.

Location: server .trunk/plugins/trunk/linters/trivy/test_data/secrets.py

high Hardcoded PEM private key in server code (.trunk/plugins/trunk/linters/trufflehog/test_data/secrets.in.py)MTC-SRC-008

A hardcoded PEM private key (a live-looking credential hardcoded in shipped code) appears in `.trunk/plugins/trunk/linters/trufflehog/test_data/secrets.in.py:11`. Secrets in source ship to everyone who installs the package and are a direct credential leak.

Evidence: PEM private key: ----…(redacted)

Fix: Remove the secret, rotate it, and load credentials from the environment or a secret store.

Location: server .trunk/plugins/trunk/linters/trufflehog/test_data/secrets.in.py

high Tool "run_shell" exposes command/code executionMTC-CAP-001

Tool "run_shell" appears to run shell commands or evaluate code (keyword "shell" in tool name). Arbitrary execution driven by model input is one of the most dangerous MCP capabilities; combined with any untrusted input it becomes RCE.

Fix: Sandbox execution, allowlist commands/arguments, and never pass model output to a shell unescaped.

Location: tool run_shell

high Dynamic code execution in server code (src/pyddock/ast_validator.py)MTC-SRC-001

In the server's implementation (`src/pyddock/ast_validator.py:247`): Evaluating strings as code is the most direct RCE primitive; if any tool input reaches it, the server executes attacker-chosen code. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: oth simple calls (e.g., eval(...)) and attribute calls (e.g., obj.eval(...)). """ if isinstan

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server src/pyddock/ast_validator.py

high Dynamic code execution in server code (src/pyddock/executor.py)MTC-SRC-001

In the server's implementation (`src/pyddock/executor.py:247`): Evaluating strings as code is the most direct RCE primitive; if any tool input reaches it, the server executes attacker-chosen code. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: f" _result = eval(compile(_last_expr, {SNIPPET_FILENAME!r}, 'eval'), _ns)", f" if _result is

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server src/pyddock/executor.py

high Shell/command execution in server code (.trunk/plugins/trunk/actions/terraform-docs/terraform-docs.py)MTC-SRC-002

In the server's implementation (`.trunk/plugins/trunk/actions/terraform-docs/terraform-docs.py:33`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: try: process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subpro

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/actions/terraform-docs/terraform-docs.py

high Shell/command execution in server code (.trunk/plugins/trunk/linters/pinact/pinact_run.py)MTC-SRC-002

In the server's implementation (`.trunk/plugins/trunk/linters/pinact/pinact_run.py:50`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: try: result = subprocess.run( [gh, "auth", "token"], shell=False, check=Fa

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/linters/pinact/pinact_run.py

high Shell/command execution in server code (.trunk/plugins/trunk/linters/snyk/test_data/js.in.js)MTC-SRC-002

In the server's implementation (`.trunk/plugins/trunk/linters/snyk/test_data/js.in.js:11`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: '); var exec = require('child_process').exec; // zip-slip var fileType = require('file-type'); var AdmZip = require('ad

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/linters/snyk/test_data/js.in.js

high Shell/command execution in server code (src/pyddock/_audit_enforcement.py)MTC-SRC-002

In the server's implementation (`src/pyddock/_audit_enforcement.py:133`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: tly redirected the spawn (the ``Popen([...], executable=...)`` spoof). Applies to every spawn — the proxy forw

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server src/pyddock/_audit_enforcement.py

high Shell/command execution in server code (src/pyddock/_process_utils.py)MTC-SRC-002

In the server's implementation (`src/pyddock/_process_utils.py:193`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: .name == "nt": subprocess.run( ["taskkill", "/F", "/T", "/PID", str(proc.pid)], captu

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server src/pyddock/_process_utils.py

high Shell/command execution in server code (src/pyddock/_subprocess_patch.py)MTC-SRC-002

In the server's implementation (`src/pyddock/_subprocess_patch.py:6`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: ll policies, and blocks os.system(). """ from __future__ import annotations import pathlib import sys from typing

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server src/pyddock/_subprocess_patch.py

medium Dynamic module load from a non-literal (src/pyddock/_enforcement.py)MTC-SRC-005

In the server's implementation (`src/pyddock/_enforcement.py:174`): Loading a module chosen at runtime (from a variable) can pull in and run attacker-influenced code paths. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: rded_import on builtins.__import__ (fires for ALL imports) Both use the same logic: top-level module in allow

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server src/pyddock/_enforcement.py

low Hardcoded AWS access key id in server code (.trunk/plugins/trunk/linters/gitleaks/test_data/basic.py)MTC-SRC-008

A hardcoded AWS access key id (a live-looking credential hardcoded in shipped code) appears in `.trunk/plugins/trunk/linters/gitleaks/test_data/basic.py:3`. Verify whether this is a real credential; if so, remove and rotate it.

Evidence: AWS access key id: AKIA…(redacted)

Fix: Remove the secret, rotate it, and load credentials from the environment or a secret store.

Location: server .trunk/plugins/trunk/linters/gitleaks/test_data/basic.py

low Mutating tool "run_shell" declares no destructiveHintMTC-CAP-005

Tool "run_shell" can mutate/egress but declares no destructiveHint. Clients that don't default to spec-safe behavior may not prompt before running it.

Fix: Declare accurate annotations, and gate destructive tools on user confirmation regardless.

Location: tool run_shell

low Dynamic code execution in packaging/dev tooling (tests/test_executor.py)MTC-SRC-001

In a packaging/dev/install script (shipped, but not the server runtime) (`tests/test_executor.py:169`): Evaluating strings as code is the most direct RCE primitive; if any tool input reaches it, the server executes attacker-chosen code. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: actual_path = eval(result.result) assert Path(actual_path).resolve() == workspace.resolve() clas

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server tests/test_executor.py

low Shell/command execution in packaging/dev tooling (.trunk/plugins/trunk/actions/uv/uv.test.ts)MTC-SRC-002

In a packaging/dev/install script (shipped, but not the server runtime) (`.trunk/plugins/trunk/actions/uv/uv.test.ts:1`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: port { execSync } from "child_process"; import * as fs from "fs"; import * as path from "path"; import { actionRunTest,

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/actions/uv/uv.test.ts

low Shell/command execution in packaging/dev tooling (.trunk/plugins/trunk/linters/eslint/eslint.test.ts)MTC-SRC-002

In a packaging/dev/install script (shipped, but not the server runtime) (`.trunk/plugins/trunk/linters/eslint/eslint.test.ts:1`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: ort { spawnSync } from "child_process"; import fs from "fs"; import path from "path"; import semver from "semver"; impor

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/linters/eslint/eslint.test.ts

low Shell/command execution in packaging/dev tooling (.trunk/plugins/trunk/linters/pinact/pinact.test.ts)MTC-SRC-002

In a packaging/dev/install script (shipped, but not the server runtime) (`.trunk/plugins/trunk/linters/pinact/pinact.test.ts:1`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: { execFileSync } from "child_process"; import * as fs from "fs"; import * as os from "os"; import * as path from "path"

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/linters/pinact/pinact.test.ts

low Shell/command execution in packaging/dev tooling (.trunk/plugins/trunk/tests/driver/driver.ts)MTC-SRC-002

In a packaging/dev/install script (shipped, but not the server runtime) (`.trunk/plugins/trunk/tests/driver/driver.ts:7`): Spawning a shell/process is command-execution capability; with unsanitized tool input it is command injection / RCE. This is read from the code itself — not from the tool description — so a poisoned server cannot hide it behind honest-looking metadata.

Evidence: StringEncoding, } from "child_process"; import { Debugger } from "debug"; import * as fs from "fs"; import * as os from

Fix: Review this call path: confirm it never receives unsanitized tool input, constrain it, or remove it. Treat a server whose code reaches these sinks as high-capability regardless of what its tools claim.

Location: server .trunk/plugins/trunk/tests/driver/driver.ts

Tools 10

Each tool and what it can reach — statically extracted from the published source.

  • fs_readfilereads sensitive data
  • run_shellruns code / shell
  • fs_appendno sensitive capability
  • fs_deleteno sensitive capability
  • fs_findno sensitive capability
  • fs_grepno sensitive capability
  • fs_statno sensitive capability
  • fs_str_replaceno sensitive capability
  • run_mcpno sensitive capability
  • run_pythonno sensitive capability

Toxic flows 1

Cross-tool combinations that form a data-exfiltration primitive (untrusted input → sensitive source → external sink).

What this scan could not see

Versions 5

Scan history per published version. The engine is deterministic — the same version always yields the same score, so a changed score means the package itself changed.

VersionScoreFindingsEngineScanned
v0.4.2 latest D 60/100 20 1.13.0 2026-08-25
v0.4.1 A 93/100 17 1.12.1 2026-08-09
v0.4.0 A 93/100 17 1.12.1 2026-07-31
v0.3.7 A 93/100 17 1.12.1 2026-07-27
v0.3.6 A 93/100 17 1.9.0 2026-07-23

Embed this score

Show this server's live Trust Score in your README, docs or website. The badge is served straight from the registry and updates automatically after every rescan — no API key needed. It links back to this page, so anyone who sees the grade can also read the findings behind it instead of taking a number on faith.

MCP Trust Score: D · 60/100
Markdown (GitHub README)
[![MCP Trust Score](https://mcptrustchecker.com/registry/pyddock/badge.svg)](https://mcptrustchecker.com/registry/pyddock)
HTML
<a href="https://mcptrustchecker.com/registry/pyddock"><img src="https://mcptrustchecker.com/registry/pyddock/badge.svg" alt="MCP Trust Score" height="20"></a>
Prefer shields.io styling? Point it at https://mcptrustchecker.com/registry/pyddock/badge.json via https://img.shields.io/endpoint?url=…

Verify this score yourself

The score above is reproducible: the same package version always yields the same result. Run it locally or over the free API — no account, no LLM, fully deterministic.

npx mcptrustchecker scan pyddock --online --registry pypi

Use the free API → How scoring works

More in Developer Tools