ai.palmyr/palmyr
version 1.0.0
- scanned 2026-10-16
- source github.com/0xArtex/Palmyr
- commit c2020a70f50c
- transport streamable-http
- files read 256
- methodology 0.2.0
- ruleset 0.1.1
No tag matching version 1.0.0 was found in this repository, so the scan read the default branch instead. The findings below describe that code, not necessarily the released version.
0measured on 99% of this axis
2 vendored or minified paths were excluded before scanning; machine-generated bundles are not the server's own code; 1 file could not be parsed and was not scanned
75
0measured on 99% of this axis
1 vulnerability could not be placed in `03` §6's table and is listed but not scored
69measured on 75% of this axis
45
The evidence
Every deduction below names the artefact that produced it. Nothing on this page was executed: the source was read, never run, and no running server was contacted.
Code Safety
Showing the 50 most severe of 151 findings on this axis. The score was computed over all of them — findings beyond the fourth of a severity still deduct at a tenth of their weight — so the remainder is omitted from this page, not from the arithmetic.
- src/routes/agent-batch.ts:20mcp-js-ssrf-metadata-endpoint (critical/medium)
The cloud instance-metadata endpoint is contacted directly — the standard path from SSRF to credential theft on a hosted server.
// absolute pathname ("/api/..."), never a full / scheme-relative / userinfo URL. // Without this an unauthenticated caller could redirect the server-side fetch to // an internal or cloud-metadata host (e.g. "@169.254.169.254/...", "//evil.tld/...") // and read the response back -- a classic SSRF. We resolve the supplied path // against the loopback base and require the resolved origin to still be that - src/routes/compute.ts:105mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
nodeFs.mkdirSync(HOST_KEY_DIR, { recursive: true }); const { execSync } = require('child_process'); const out = String(execSync(`ssh-keyscan -T 8 -t ed25519,rsa,ecdsa ${ip}`, { timeout: 12000, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], }) || ''); - src/routes/compute.ts:105mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
nodeFs.mkdirSync(HOST_KEY_DIR, { recursive: true }); const { execSync } = require('child_process'); const out = String(execSync(`ssh-keyscan -T 8 -t ed25519,rsa,ecdsa ${ip}`, { timeout: 12000, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], }) || ''); - src/routes/compute.ts:180mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
const op = opts.append ? '>>' : '>'; const chmod = opts.chmod ? ` && chmod ${assertIdent(opts.chmod, 'chmod').toString()} ${remotePath}` : ''; execSync(`${ssh} "echo '${b64}' | base64 -d ${op} ${remotePath}${chmod}"`, { timeout: opts.timeout ?? 15000 }); } - src/routes/compute.ts:180mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
const op = opts.append ? '>>' : '>'; const chmod = opts.chmod ? ` && chmod ${assertIdent(opts.chmod, 'chmod').toString()} ${remotePath}` : ''; execSync(`${ssh} "echo '${b64}' | base64 -d ${op} ${remotePath}${chmod}"`, { timeout: opts.timeout ?? 15000 }); } - src/routes/compute.ts:1155mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// 1. Inject user's public key via base64 (never interpolate user input into shell) execSync(`${ssh} "mkdir -p ~/.ssh && chmod 700 ~/.ssh"`, { timeout: 20000 }); sshWriteFile(ssh, '/root/.ssh/authorized_keys', publicKey.trim() + '\n', { append: true, chmod: '600', timeout: 20000 }); - src/routes/compute.ts:1155mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// 1. Inject user's public key via base64 (never interpolate user input into shell) execSync(`${ssh} "mkdir -p ~/.ssh && chmod 700 ~/.ssh"`, { timeout: 20000 }); sshWriteFile(ssh, '/root/.ssh/authorized_keys', publicKey.trim() + '\n', { append: true, chmod: '600', timeout: 20000 }); - src/routes/compute.ts:1159mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// 2. Remove platform temp key from authorized_keys execSync(`${ssh} "sed -i '/palmyr-platform-temp/d' ~/.ssh/authorized_keys"`, { timeout: 10000 }); // 3. Lock root password - src/routes/compute.ts:1159mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// 2. Remove platform temp key from authorized_keys execSync(`${ssh} "sed -i '/palmyr-platform-temp/d' ~/.ssh/authorized_keys"`, { timeout: 10000 }); // 3. Lock root password - src/routes/compute.ts:1162mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// 3. Lock root password execSync(`${ssh} "passwd -l root"`, { timeout: 10000 }); // 4. Delete root password from our database — we can never access again - src/routes/compute.ts:1162mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// 3. Lock root password execSync(`${ssh} "passwd -l root"`, { timeout: 10000 }); // 4. Delete root password from our database — we can never access again - src/routes/compute.ts:1198mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Check reachability + OpenClaw version const versionOut = execSync(`${ssh} "openclaw --version 2>/dev/null || echo NOT_INSTALLED"`, { timeout: 15000, encoding: "utf-8" }).trim(); result.reachable = true; - src/routes/compute.ts:1198mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Check reachability + OpenClaw version const versionOut = execSync(`${ssh} "openclaw --version 2>/dev/null || echo NOT_INSTALLED"`, { timeout: 15000, encoding: "utf-8" }).trim(); result.reachable = true; - src/routes/compute.ts:1208mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Check provision metadata try { const provisionJson = execSync(`${ssh} "cat /etc/openclaw/provision.json 2>/dev/null || echo {}"`, { timeout: 10000, encoding: "utf-8" }).trim(); result.provision_log = JSON.parse(provisionJson); result.hardened = result.provision_log?.hardened || false; - src/routes/compute.ts:1208mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Check provision metadata try { const provisionJson = execSync(`${ssh} "cat /etc/openclaw/provision.json 2>/dev/null || echo {}"`, { timeout: 10000, encoding: "utf-8" }).trim(); result.provision_log = JSON.parse(provisionJson); result.hardened = result.provision_log?.hardened || false; - src/routes/compute.ts:1215mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Check firewall try { const ufwStatus = execSync(`${ssh} "ufw status 2>/dev/null | head -1 || echo inactive"`, { timeout: 10000, encoding: "utf-8" }).trim(); result.firewall = ufwStatus.includes("active") ? "active" : "inactive"; } catch (e) { result.firewall = "unknown"; } - src/routes/compute.ts:1215mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Check firewall try { const ufwStatus = execSync(`${ssh} "ufw status 2>/dev/null | head -1 || echo inactive"`, { timeout: 10000, encoding: "utf-8" }).trim(); result.firewall = ufwStatus.includes("active") ? "active" : "inactive"; } catch (e) { result.firewall = "unknown"; } - src/routes/compute.ts:1260mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// 1. Ensure directory exists execSync(`${ssh} "mkdir -p /root/.openclaw/workspace"`, { timeout: 10000 }); // 2. Read existing config (or start fresh) - src/routes/compute.ts:1260mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// 1. Ensure directory exists execSync(`${ssh} "mkdir -p /root/.openclaw/workspace"`, { timeout: 10000 }); // 2. Read existing config (or start fresh) - src/routes/compute.ts:1265mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
let config: any = {}; try { const existing = execSync(`${ssh} "cat /root/.openclaw/openclaw.json 2>/dev/null || echo '{}'"`, { timeout: 10000, encoding: "utf-8" }).trim(); config = JSON.parse(existing); } catch (e) { config = {}; } - src/routes/compute.ts:1265mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
let config: any = {}; try { const existing = execSync(`${ssh} "cat /root/.openclaw/openclaw.json 2>/dev/null || echo '{}'"`, { timeout: 10000, encoding: "utf-8" }).trim(); config = JSON.parse(existing); } catch (e) { config = {}; } - src/routes/compute.ts:1302mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
} }; execSync(`${ssh} "mkdir -p /root/.openclaw/agents/main/agent"`, { timeout: 10000 }); sshWriteFile(ssh, '/root/.openclaw/agents/main/agent/auth-profiles.json', JSON.stringify(authProfile, null, 2)); } else { - src/routes/compute.ts:1302mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
} }; execSync(`${ssh} "mkdir -p /root/.openclaw/agents/main/agent"`, { timeout: 10000 }); sshWriteFile(ssh, '/root/.openclaw/agents/main/agent/auth-profiles.json', JSON.stringify(authProfile, null, 2)); } else { - src/routes/compute.ts:1310mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Idempotent: remove old line, then write user-provided key via base64 stdin // (never interpolate anthropicKey into the shell string). execSync(`${ssh} "grep -v '^${envVar}=' /etc/environment > /tmp/env.tmp 2>/dev/null || true"`, { timeout: 10000 }); sshWriteFile(ssh, '/tmp/env.tmp', `${envVar}=${anthropicKey}\n`, { append: true }); execSync(`${ssh} "mv /tmp/env.tmp /etc/environment"`, { timeout: 10000 }); - src/routes/compute.ts:1310mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Idempotent: remove old line, then write user-provided key via base64 stdin // (never interpolate anthropicKey into the shell string). execSync(`${ssh} "grep -v '^${envVar}=' /etc/environment > /tmp/env.tmp 2>/dev/null || true"`, { timeout: 10000 }); sshWriteFile(ssh, '/tmp/env.tmp', `${envVar}=${anthropicKey}\n`, { append: true }); execSync(`${ssh} "mv /tmp/env.tmp /etc/environment"`, { timeout: 10000 }); - src/routes/compute.ts:1312mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
execSync(`${ssh} "grep -v '^${envVar}=' /etc/environment > /tmp/env.tmp 2>/dev/null || true"`, { timeout: 10000 }); sshWriteFile(ssh, '/tmp/env.tmp', `${envVar}=${anthropicKey}\n`, { append: true }); execSync(`${ssh} "mv /tmp/env.tmp /etc/environment"`, { timeout: 10000 }); } } - src/routes/compute.ts:1312mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
execSync(`${ssh} "grep -v '^${envVar}=' /etc/environment > /tmp/env.tmp 2>/dev/null || true"`, { timeout: 10000 }); sshWriteFile(ssh, '/tmp/env.tmp', `${envVar}=${anthropicKey}\n`, { append: true }); execSync(`${ssh} "mv /tmp/env.tmp /etc/environment"`, { timeout: 10000 }); } } - src/routes/compute.ts:1349mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
const configJson = JSON.stringify(config, null, 2); const configB64 = Buffer.from(configJson).toString('base64'); execSync(`${ssh} "echo '${configB64}' | base64 -d > /root/.openclaw/openclaw.json"`, { timeout: 10000 }); // 6. Create workspace files if agent name provided - src/routes/compute.ts:1349mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
const configJson = JSON.stringify(config, null, 2); const configB64 = Buffer.from(configJson).toString('base64'); execSync(`${ssh} "echo '${configB64}' | base64 -d > /root/.openclaw/openclaw.json"`, { timeout: 10000 }); // 6. Create workspace files if agent name provided - src/routes/compute.ts:1380mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
const svcB64 = Buffer.from(serviceFile).toString('base64'); execSync(`${ssh} "echo '${svcB64}' | base64 -d > /etc/systemd/system/openclaw.service"`, { timeout: 10000 }); execSync(`${ssh} "systemctl daemon-reload && systemctl enable openclaw && systemctl restart openclaw"`, { timeout: 20000 }); - src/routes/compute.ts:1380mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
const svcB64 = Buffer.from(serviceFile).toString('base64'); execSync(`${ssh} "echo '${svcB64}' | base64 -d > /etc/systemd/system/openclaw.service"`, { timeout: 10000 }); execSync(`${ssh} "systemctl daemon-reload && systemctl enable openclaw && systemctl restart openclaw"`, { timeout: 20000 }); - src/routes/compute.ts:1381mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
const svcB64 = Buffer.from(serviceFile).toString('base64'); execSync(`${ssh} "echo '${svcB64}' | base64 -d > /etc/systemd/system/openclaw.service"`, { timeout: 10000 }); execSync(`${ssh} "systemctl daemon-reload && systemctl enable openclaw && systemctl restart openclaw"`, { timeout: 20000 }); // 6. Verify it started - src/routes/compute.ts:1381mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
const svcB64 = Buffer.from(serviceFile).toString('base64'); execSync(`${ssh} "echo '${svcB64}' | base64 -d > /etc/systemd/system/openclaw.service"`, { timeout: 10000 }); execSync(`${ssh} "systemctl daemon-reload && systemctl enable openclaw && systemctl restart openclaw"`, { timeout: 20000 }); // 6. Verify it started - src/routes/compute.ts:1386mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
let running = false; try { const status = execSync(`${ssh} "systemctl is-active openclaw 2>/dev/null || echo inactive"`, { timeout: 10000, encoding: "utf-8" }).trim(); running = status === "active"; } catch (e) {} - src/routes/compute.ts:1386mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
let running = false; try { const status = execSync(`${ssh} "systemctl is-active openclaw 2>/dev/null || echo inactive"`, { timeout: 10000, encoding: "utf-8" }).trim(); running = status === "active"; } catch (e) {} - src/routes/compute.ts:1428mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
let config: any = {}; try { const existing = execSync(`${ssh} "cat /root/.openclaw/openclaw.json 2>/dev/null || echo '{}'"`, { timeout: 10000, encoding: "utf-8" }).trim(); config = JSON.parse(existing); } catch (e) { config = {}; } - src/routes/compute.ts:1428mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
let config: any = {}; try { const existing = execSync(`${ssh} "cat /root/.openclaw/openclaw.json 2>/dev/null || echo '{}'"`, { timeout: 10000, encoding: "utf-8" }).trim(); config = JSON.parse(existing); } catch (e) { config = {}; } - src/routes/compute.ts:1445mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Clear auth-profiles.json try { execSync(`${ssh} "rm -f /root/.openclaw/agents/main/agent/auth-profiles.json"`, { timeout: 10000 }); } catch (e) {} // Clear env var on server - src/routes/compute.ts:1445mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Clear auth-profiles.json try { execSync(`${ssh} "rm -f /root/.openclaw/agents/main/agent/auth-profiles.json"`, { timeout: 10000 }); } catch (e) {} // Clear env var on server - src/routes/compute.ts:1449mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Clear env var on server try { execSync(`${ssh} "grep -v '_API_KEY' /etc/environment > /tmp/env.tmp 2>/dev/null; mv /tmp/env.tmp /etc/environment"`, { timeout: 10000 }); } catch (e) {} } - src/routes/compute.ts:1449mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Clear env var on server try { execSync(`${ssh} "grep -v '_API_KEY' /etc/environment > /tmp/env.tmp 2>/dev/null; mv /tmp/env.tmp /etc/environment"`, { timeout: 10000 }); } catch (e) {} } - src/routes/compute.ts:1456mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
const configJson = JSON.stringify(config, null, 2); const configB64 = Buffer.from(configJson).toString('base64'); execSync(`${ssh} "echo '${configB64}' | base64 -d > /root/.openclaw/openclaw.json"`, { timeout: 10000 }); // Restart OpenClaw - src/routes/compute.ts:1456mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
const configJson = JSON.stringify(config, null, 2); const configB64 = Buffer.from(configJson).toString('base64'); execSync(`${ssh} "echo '${configB64}' | base64 -d > /root/.openclaw/openclaw.json"`, { timeout: 10000 }); // Restart OpenClaw - src/routes/compute.ts:1459mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Restart OpenClaw execSync(`${ssh} "systemctl restart openclaw 2>/dev/null || true"`, { timeout: 15000 }); res.json({ success: true, removed: remove }); - src/routes/compute.ts:1459mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Restart OpenClaw execSync(`${ssh} "systemctl restart openclaw 2>/dev/null || true"`, { timeout: 15000 }); res.json({ success: true, removed: remove }); - src/routes/compute.ts:1491mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Create skills directory execSync(`${ssh} "mkdir -p /root/.openclaw/workspace/skills"`, { timeout: 10000 }); // Install skill via git clone or copy from clawhub - src/routes/compute.ts:1491mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Create skills directory execSync(`${ssh} "mkdir -p /root/.openclaw/workspace/skills"`, { timeout: 10000 }); // Install skill via git clone or copy from clawhub - src/routes/compute.ts:1506mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
// Tar + pipe to remote (skillName is validated ident) const parentDir = require("path").dirname(sourcePath); execSync(`tar -C ${parentDir} -cf - ${skillName} | ${ssh} "tar -C /root/.openclaw/workspace/skills -xf -"`, { timeout: 30000 }); } else if (skillUrl) { // Git clone — skillUrl and skillName are validated above - src/routes/compute.ts:1506mcp-js-shell-exec-template-literal (critical/medium)
A shell command is built from a template literal with interpolation. Quoting inside a template does not escape shell metacharacters.
// Tar + pipe to remote (skillName is validated ident) const parentDir = require("path").dirname(sourcePath); execSync(`tar -C ${parentDir} -cf - ${skillName} | ${ssh} "tar -C /root/.openclaw/workspace/skills -xf -"`, { timeout: 30000 }); } else if (skillUrl) { // Git clone — skillUrl and skillName are validated above - src/routes/compute.ts:1509mcp-js-shell-exec-nonliteral (critical/medium)
A shell is spawned on a value that is not a string literal. child_process .exec and execSync run their argument through /bin/sh, so any caller-supplied component is shell syntax, not data.
} else if (skillUrl) { // Git clone — skillUrl and skillName are validated above execSync(`${ssh} "git clone --depth 1 ${skillUrl} ${skillDir} 2>/dev/null || echo 'clone failed'"`, { timeout: 30000 }); } else { return res.status(400).json({ error: `Skill '${skillName}' not found locally and no URL provided` });
Auth Posture
- authentication_model
auth enforcement present at a call site in the source (auth middleware) and documented in the README; "refused without credentials" (`03` §4) established by reading the code rather than by connecting
- transport_security
declared endpoint(s) are HTTPS: https://palmyr.ai/mcp; scored 80, not 100: `03` §4 reserves 100 for HTTPS *with HSTS*, and an HSTS header can only be seen by connecting, which `04` §9 does not do. This is an unverifiable band, not an observed absence.
- secret_handling
Private Key at cli/compute-ssh.ts:34; Private Key at public/dashboard.html:3357; …and 92 more matches
- authorization_granularity
34 tool registrations with conditional access logic present in the same source
Dependency Health
Showing the 50 most severe of 176 findings on this axis. The score was computed over all of them — findings beyond the fourth of a severity still deduct at a tenth of their weight — so the remainder is omitted from this page, not from the arithmetic.
- package-lock.json@whiskeysockets/baileys 7.0.0-rc.9 — GHSA-qvv5-jq5g-4cgg
direct, CVSS 9.3
https://osv.dev/vulnerability/GHSA-qvv5-jq5g-4cgg - package-lock.jsonprotobufjs 6.8.8 — GHSA-xq3m-2v4x-88gg
transitive, CVSS 9.8, fixed in 7.5.5
https://osv.dev/vulnerability/GHSA-xq3m-2v4x-88gg - package-lock.jsonprotobufjs 7.5.4 — GHSA-xq3m-2v4x-88gg
transitive, CVSS 9.8, fixed in 7.5.5
https://osv.dev/vulnerability/GHSA-xq3m-2v4x-88gg - cli/package-lock.jsonshell-quote 1.8.3 — GHSA-w7jw-789q-3m8p
transitive, CVSS 9.2, fixed in 1.8.4
https://osv.dev/vulnerability/GHSA-w7jw-789q-3m8p - package-lock.jsonproxy-addr 2.0.7 — GHSA-jqcg-44mw-7w3h
transitive, CVSS 9.1, fixed in 2.0.8
https://osv.dev/vulnerability/GHSA-jqcg-44mw-7w3h - frontend/discovery/package-lock.jsonvite 6.4.2 — GHSA-fx2h-pf6j-xcff
direct, CVSS 8.2, fixed in 6.4.3
https://osv.dev/vulnerability/GHSA-fx2h-pf6j-xcff - package-lock.json@modelcontextprotocol/sdk 1.29.0 — GHSA-6qxp-vccf-f47h
direct, CVSS 7.5, fixed in 1.31.0
https://osv.dev/vulnerability/GHSA-6qxp-vccf-f47h - package-lock.jsoncompression 1.8.1 — GHSA-vc2v-76pw-4v95
direct, CVSS 7.5, fixed in 1.8.2
https://osv.dev/vulnerability/GHSA-vc2v-76pw-4v95 - package-lock.jsonhttp-proxy-middleware 3.0.5 — GHSA-gcq2-9pq2-cxqm
direct, CVSS 7.5, fixed in 3.0.7
https://osv.dev/vulnerability/GHSA-gcq2-9pq2-cxqm - cli/package-lock.jsonuuid 8.3.2 — GHSA-w5hq-g745-h8pq
direct, CVSS 7.5, fixed in 11.1.1
https://osv.dev/vulnerability/GHSA-w5hq-g745-h8pq - package-lock.jsonuuid 11.1.0 — GHSA-w5hq-g745-h8pq
direct, CVSS 7.5, fixed in 11.1.1
https://osv.dev/vulnerability/GHSA-w5hq-g745-h8pq - package-lock.jsonuuid 8.3.2 — GHSA-w5hq-g745-h8pq
direct, CVSS 7.5, fixed in 11.1.1
https://osv.dev/vulnerability/GHSA-w5hq-g745-h8pq - cli/package-lock.jsonws 7.5.10 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 7.5.11
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - cli/package-lock.jsonws 8.17.1 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 8.21.0
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - cli/package-lock.jsonws 8.20.1 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 8.21.0
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - package-lock.jsonws 7.5.10 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 7.5.11
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - package-lock.jsonws 8.17.1 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 8.21.0
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - package-lock.jsonws 8.18.3 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 8.21.0
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - package-lock.jsonws 8.20.0 — GHSA-96hv-2xvq-fx4p
direct, CVSS 7.5, fixed in 8.21.0
https://osv.dev/vulnerability/GHSA-96hv-2xvq-fx4p - package-lock.jsonsharp 0.34.5 — GHSA-rgj7-g3m4-5g8c
transitive, CVSS 8.9, fixed in 0.35.4
https://osv.dev/vulnerability/GHSA-rgj7-g3m4-5g8c - package-lock.jsonsharp 0.34.5 — GHSA-wq5f-xc86-pv6w
transitive, CVSS 8.9, fixed in 0.35.5
https://osv.dev/vulnerability/GHSA-wq5f-xc86-pv6w - package-lock.jsonaxios 1.13.4 — GHSA-35jp-ww65-95wh
transitive, CVSS 8.7, fixed in 1.16.0
https://osv.dev/vulnerability/GHSA-35jp-ww65-95wh - package-lock.jsonbraces 3.0.3 — GHSA-vfj7-8cjw-p6xm
transitive, CVSS 8.7
https://osv.dev/vulnerability/GHSA-vfj7-8cjw-p6xm - package-lock.jsonform-data 4.0.5 — GHSA-hmw2-7cc7-3qxx
transitive, CVSS 8.7, fixed in 4.0.6
https://osv.dev/vulnerability/GHSA-hmw2-7cc7-3qxx - package-lock.jsonminimatch 3.1.2 — GHSA-3ppc-4f35-3m26
transitive, CVSS 8.7, fixed in 3.1.3
https://osv.dev/vulnerability/GHSA-3ppc-4f35-3m26 - cli/package-lock.jsonshell-quote 1.8.3 — GHSA-395f-4hp3-45gv
transitive, CVSS 8.7, fixed in 1.9.0
https://osv.dev/vulnerability/GHSA-395f-4hp3-45gv - frontend/discovery/package-lock.jsonsource-map-js 1.2.1 — GHSA-68fv-2mgg-jv7q
transitive, CVSS 8.7, fixed in 1.2.2
https://osv.dev/vulnerability/GHSA-68fv-2mgg-jv7q - package-lock.jsonnodemailer 8.0.5 — GHSA-r7g4-qg5f-qqm2
transitive, CVSS 8.3, fixed in 8.0.8
https://osv.dev/vulnerability/GHSA-r7g4-qg5f-qqm2 - package-lock.jsonaxios 1.13.4 — GHSA-542g-h47m-68v8
transitive, CVSS 8.2, fixed in 1.20.0
https://osv.dev/vulnerability/GHSA-542g-h47m-68v8 - package-lock.jsonaxios 1.13.4 — GHSA-p92q-9vqr-4j8v
transitive, CVSS 8.2, fixed in 1.16.0
https://osv.dev/vulnerability/GHSA-p92q-9vqr-4j8v - frontend/discovery/package-lock.jsonnanoid 3.3.12 — GHSA-28wg-ghj8-5hjv
transitive, CVSS 8.2, fixed in 3.3.16
https://osv.dev/vulnerability/GHSA-28wg-ghj8-5hjv - frontend/discovery/package-lock.jsonnanoid 3.3.12 — GHSA-2v37-7h3g-55p8
transitive, CVSS 8.2, fixed in 3.3.18
https://osv.dev/vulnerability/GHSA-2v37-7h3g-55p8 - package-lock.jsonlodash 4.17.23 — GHSA-r5fr-rjxr-66jc
transitive, CVSS 8.1, fixed in 4.18.0
https://osv.dev/vulnerability/GHSA-r5fr-rjxr-66jc - package-lock.jsonprotobufjs 6.8.8 — GHSA-75px-5xx7-5xc7
transitive, CVSS 8.1, fixed in 7.5.6
https://osv.dev/vulnerability/GHSA-75px-5xx7-5xc7 - package-lock.jsonprotobufjs 7.5.4 — GHSA-75px-5xx7-5xc7
transitive, CVSS 8.1, fixed in 7.5.6
https://osv.dev/vulnerability/GHSA-75px-5xx7-5xc7 - cli/package-lock.jsonbigint-buffer 1.1.5 — GHSA-3gc7-fjrx-p6mg
transitive, CVSS 7.7
https://osv.dev/vulnerability/GHSA-3gc7-fjrx-p6mg - package-lock.jsonbigint-buffer 1.1.5 — GHSA-3gc7-fjrx-p6mg
transitive, CVSS 7.7
https://osv.dev/vulnerability/GHSA-3gc7-fjrx-p6mg - package-lock.jsonbrace-expansion 1.1.12 — GHSA-3jxr-9vmj-r5cp
transitive, CVSS 7.7, fixed in 1.1.16
https://osv.dev/vulnerability/GHSA-3jxr-9vmj-r5cp - package-lock.jsonip-address 10.2.0 — GHSA-mwp4-54f8-5fhr
transitive, CVSS 7.7, fixed in 10.3.1
https://osv.dev/vulnerability/GHSA-mwp4-54f8-5fhr - package-lock.jsonprotobufjs 6.8.8 — GHSA-66ff-xgx4-vchm
transitive, CVSS 7.7, fixed in 7.5.6
https://osv.dev/vulnerability/GHSA-66ff-xgx4-vchm - package-lock.jsonprotobufjs 7.5.4 — GHSA-66ff-xgx4-vchm
transitive, CVSS 7.7, fixed in 7.5.6
https://osv.dev/vulnerability/GHSA-66ff-xgx4-vchm - package-lock.jsonaxios 1.13.4 — GHSA-43fc-jf86-j433
transitive, CVSS 7.5, fixed in 1.13.5
https://osv.dev/vulnerability/GHSA-43fc-jf86-j433 - package-lock.jsonaxios 1.13.4 — GHSA-62hf-57xw-28j9
transitive, CVSS 7.5, fixed in 1.15.1
https://osv.dev/vulnerability/GHSA-62hf-57xw-28j9 - package-lock.jsonaxios 1.13.4 — GHSA-777c-7fjr-54vf
transitive, CVSS 7.5, fixed in 1.16.0
https://osv.dev/vulnerability/GHSA-777c-7fjr-54vf - package-lock.jsonaxios 1.13.4 — GHSA-hfxv-24rg-xrqf
transitive, CVSS 7.5, fixed in 1.16.0
https://osv.dev/vulnerability/GHSA-hfxv-24rg-xrqf - package-lock.jsonaxios 1.13.4 — GHSA-j5f8-grm9-p9fc
transitive, CVSS 7.5, fixed in 1.16.0
https://osv.dev/vulnerability/GHSA-j5f8-grm9-p9fc - package-lock.jsonbrace-expansion 1.1.12 — GHSA-6j4f-fj2g-mc7p
transitive, CVSS 7.5, fixed in 1.1.19
https://osv.dev/vulnerability/GHSA-6j4f-fj2g-mc7p - package-lock.jsonbrace-expansion 1.1.12 — GHSA-mh99-v99m-4gvg
transitive, CVSS 7.5, fixed in 1.1.17
https://osv.dev/vulnerability/GHSA-mh99-v99m-4gvg - package-lock.jsonbrace-expansion 1.1.12 — GHSA-qhr7-859c-m2p7
transitive, CVSS 7.5, fixed in 1.1.20
https://osv.dev/vulnerability/GHSA-qhr7-859c-m2p7 - package-lock.jsonbrace-expansion 1.1.12 — GHSA-rgw5-rvv9-x895
transitive, CVSS 7.5, fixed in 1.1.18
https://osv.dev/vulnerability/GHSA-rgw5-rvv9-x895
Maintenance
- recency
last commit 33 day(s) before 2026-10-16
- issue_responsiveness
median over 4 issue(s) in the last 6 months: 22.3 day(s) to first maintainer comment
- release_cadence
median release gap 5 days (by releases), last release 145 day(s) ago
- bus_factor
this repository's 12-month history is longer than the bounded walk `04` §7 performs, and the authors found so far span more than one of `03` §5's bands. A limit of ours, not a finding about the server.
- repository_signals
`03` §5 scores this by quartile WITHIN the server's category, which needs a distribution across every scanned server and so cannot be computed while scanning one. It is a post-pass over the crawl and that pass does not exist yet.
Transparency
- license
LICENSE present with no SPDX-License-Identifier tag; identified as 'MIT' from its text
- readme_quality
README.md: installation instructions (+25), configuration documented (+25)
- declared_scopes
neither the README nor the MCP manifest documents what the server accesses or what side effects it has
- changelog
no CHANGELOG in the fetched source. `03` §7's partial credit for tagged releases carrying release notes is not applied here — that needs the forge API, which this check does not call
- security_contact
SECURITY.md present
Contest a finding
Every number here comes from a rule reading published source, and rules get things wrong. If something on this page is incorrect — or correct but mitigated by a check the rule cannot see — open an issue and we answer it in writing. A finding we got wrong is removed and the rule is fixed; one that stands is answered on the record.
Anyone can file: the maintainer, a researcher who disagrees with the classification, or a user who tested the server and could not reproduce it. Name this server and the rule or advisory ID shown beside the finding above. We aim to reply within five business days and to resolve within ten.