MCP, MCP server
devduck
devduck, an MCP server listed in the PlugVet directory.
Compatibility: Not stated.
Grade D
Two or more Medium findings, or a High. Only try it in a sandbox.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
INSTALL_REMOTE_SCRIPT NETWORK_HOST_FROM_INPUT
Why this grade
- INSTALL_REMOTE_SCRIPT Medium
Fetches a script from the network and runs it (a pipe to a shell, or an install hook with a URL).
action.yml, line 127
curl -LsSf https://astral.sh/uv/install.sh | sh - NETWORK_HOST_FROM_INPUT Medium
A file takes a URL or endpoint as input and has no fixed host list.
devduck/tools/_tray_app.py, line 161
rumps.MenuItem(f" {ws_status} WebSocket (8080)", callback=self.toggle_ws)
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
If you think this grade is wrong, email [email protected] with the entry link and your evidence. We aim to acknowledge within two working days and decide within seven. If we confirm an error, we aim to correct it within 24 hours of confirming it. These are aims, not guarantees.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Concern
can delete files.
PERMISSION_DELETE_FILES
devduck/__init__.py, line 2830
subprocess.run(["ollama", "serve"], check=False, timeout=2)
devduck/__init__.py, line 2868
os.remove(socket_path)
devduck/__init__.py, line 3878
process = subprocess.Popen(
Show more
devduck/__init__.py, line 3944
deploy_process = subprocess.Popen(
devduck/__init__.py, line 4072
result = subprocess.run(
devduck/__init__.py, line 4145
result = subprocess.run(
devduck/tools/_ambient_input.py, line 311
subprocess.run(
devduck/tools/agentcore_config.py, line 232
process = subprocess.Popen(
devduck/tools/agentcore_config.py, line 271
launch_process = subprocess.Popen(
devduck/tools/editor.py, line 739
os.remove(backup_path)
devduck/tools/neuralset.py, line 145
shutil.rmtree(NEURALSET_REPO_DIR, ignore_errors=True)
devduck/tools/neuralset.py, line 426
shutil.rmtree(NEURALSET_CACHE)
Install and update
Serious
install fetches a script from the network.
INSTALL_REMOTE_SCRIPT
requirements.txt, line 1
devduck
action.yml, line 127
curl -LsSf https://astral.sh/uv/install.sh | sh
Network
Serious
accepts a host from input, with no fixed list in this file.
NETWORK_HOST_FROM_INPUT
devduck/tools/_tray_app.py, line 161
rumps.MenuItem(f" {ws_status} WebSocket (8080)", callback=self.toggle_ws)
devduck/tools/agentcore_proxy.py, line 80
resp = requests.get(url, headers=headers, timeout=10)
devduck/tools/agentcore_proxy.py, line 93
repo_resp = requests.get(repo_url, headers=headers, timeout=10)
Show more
devduck/tools/agentcore_proxy.py, line 97
runs_resp = requests.get(
devduck/tools/agentcore_proxy.py, line 175
resp = requests.post(url, headers=headers, json=data, timeout=30)
devduck/tools/agentcore_proxy.py, line 1529
lambda: requests.get(
devduck/tools/agentcore_proxy.py, line 1576
None, lambda: requests.get(run_url, headers=headers, timeout=10)
devduck/tools/agentcore_proxy.py, line 1605
lambda: requests.get(logs_url, headers=headers, timeout=30),
devduck/tools/browse.py, line 523
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=2)
devduck/tools/browse.py, line 536
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}/json", timeout=2)
devduck/tools/browse.py, line 587
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}/json/version", timeout=3)
devduck/tools/browse.py, line 597
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}/json", timeout=3)
devduck/tools/browse.py, line 720
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}/json", timeout=3)
devduck/tools/browse.py, line 737
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}/json", timeout=3)
devduck/tools/browse.py, line 750
urllib.request.urlopen(f"http://127.0.0.1:{port}/json/activate/{tab_id}", timeout=3)
devduck/tools/scraper.py, line 155
response = requests.get(
Secrets
Concern
reads a credential or environment file.
SECRETS_ENV_READ SECRETS_PATH_DOTENV
devduck/__init__.py, line 2403
max_tokens = int(os.getenv("STRANDS_MAX_TOKENS", "60000"))
devduck/__init__.py, line 2411
if os.getenv("AWS_BEARER_TOKEN_BEDROCK"):
devduck/__init__.py, line 2423
if os.getenv("ANTHROPIC_API_KEY"):
Show more
devduck/__init__.py, line 2427
elif os.getenv("OPENAI_API_KEY"):
devduck/__init__.py, line 2431
elif os.getenv("GITHUB_TOKEN") or os.getenv("PAT_TOKEN"):
devduck/__init__.py, line 2435
elif os.getenv("GOOGLE_API_KEY") or os.getenv("GEMINI_API_KEY"):
devduck/__init__.py, line 2439
elif os.getenv("COHERE_API_KEY"):
devduck/__init__.py, line 2443
elif os.getenv("WRITER_API_KEY"):
devduck/tools/service.py, line 192
return (f"/etc/devduck/{self.service_name}.env"
devduck/tools/service.py, line 194
else f"{self.home}/.config/devduck/{self.service_name}.env")
devduck/tools/service.py, line 196
return (f"/Library/Application Support/devduck/{self.service_name}.env"
devduck/tools/service.py, line 198
else f"{self.home}/Library/Application Support/devduck/{self.service_name}.env")
.env.example, line 2
# Copy to .env and fill in what you need. All values are optional - DevDuck
README.md, line 442
| Env file | `~/.config/devduck/devduck-<name>.env` |
docker-compose.yml, line 17
- .env
docs/guide/self-replication.md, line 182
| Env file | `~/.config/devduck/devduck-<name>.env` |
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Concern
contains an encoded blob in a file that should be readable.
OBFUSCATION_ENCODED_BLOB
README.md, line 9
[.
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit f6b226cd37a2. can delete files. install fetches a script from the network. accepts a host from input, with no fixed list in this file. reads a credential or environment file. contains an encoded blob in a file that should be readable.
Date and source
Date checked:
github.com
Commit graded: f6b226cd37a27bc6701ecf1563719ea46f2b9eb7
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.