Grades are a hygiene check, not a security guarantee.

MCP, MCP server

Synapse Ai

Synapse Ai, an MCP server listed in the PlugVet directory.

Compatibility: Not stated.

Grade D

Two or more Medium findings, or a High finding. Only try it in a sandbox.

Graded by PlugVetRubric v2

Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.

Rescanned at commit 9ee485d09068, unchanged since the check below.

INSTALL_REMOTE_SCRIPT SECRETS_PATH_CREDENTIAL

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).

    setup.py, line 607 f'{curl} -LsSf https://astral.sh/uv/install.sh | sh',

  • SECRETS_PATH_CREDENTIAL Medium

    Mentions a credential store path (~/.ssh, id_rsa, .npmrc, .aws/credentials, credentials.json, .netrc).

    setup.py, line 57 CREDENTIALS_FILE = os.path.join(DATA_DIR, "credentials.json")

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

    hatch_build.py, line 19

    result = subprocess.run(["bash", str(script)], cwd=root)

    launch_browser.py, line 50

    subprocess.Popen([browser_cmd, f"--app={url}"])

    setup.py, line 158

    subprocess.check_call(["brew", "install", "node"])

    Show more

    setup.py, line 173

    subprocess.check_call(["curl", "-fsSL", "https://deb.nodesource.com/setup_20.x", "-o", "nodesource_setup.sh"])

    setup.py, line 174

    subprocess.check_call(["sudo", "bash", "nodesource_setup.sh"])

    setup.py, line 175

    subprocess.check_call(["sudo", "apt-get", "install", "-y", "nodejs"])

    setup.py, line 176

    subprocess.check_call(["rm", "nodesource_setup.sh"])

    setup.py, line 181

    subprocess.check_call(["sudo", "apt-get", "update"])

    setup.py, line 1708

    shutil.rmtree(VENV_DIR)

    setup.py, line 1762

    shutil.rmtree(node_modules)

    setup.py, line 2120

    os.remove(pid_path)

    setup.py, line 2404

    os.remove(plist_path)

    setup.py, line 2469

    os.remove(service_path)

    backend/core/mcp_client.py, line 130

    os.remove(p)

    backend/core/session.py, line 177

    os.remove(path)

    backend/core/orchestration/steps.py, line 587

    shutil.rmtree(tmp_dir, ignore_errors=True)

  • Install and update

    Serious

    install fetches a script from the network. README documents an installer that pipes a download into a shell. The docs document an installer that pipes a download into a shell.

    INSTALL_REMOTE_SCRIPT INSTALL_DOCUMENTED_INSTALLER

    README.md, line 36

    curl -sSL https://raw.githubusercontent.com/synapseorch-ai/synapse-ai/main/setup.sh | bash

    setup.py, line 607

    f'{curl} -LsSf https://astral.sh/uv/install.sh | sh',

    setup.py, line 612

    f'{wget} -qO- https://astral.sh/uv/install.sh | sh',

    Show more

    setup.sh, line 122

    curl -LsSf https://astral.sh/uv/install.sh | sh

    setup.sh, line 124

    wget -qO- https://astral.sh/uv/install.sh | sh

    setup.sh, line 141

    echo " Install manually: curl -LsSf https://astral.sh/uv/install.sh | sh"

    backend/core/mcp_client.py, line 537

    hints = {"uvx": "Install uv: curl -LsSf https://astral.sh/uv/install.sh | sh",

    scripts/lock-deps.sh, line 32

    echo " install: curl -LsSf https://astral.sh/uv/install.sh | sh" >&2

  • Network

    Concern

    can reach a host that is not written as a fixed address.

    NETWORK_NO_FIXED_HOST

    setup.py, line 603

    curl = shutil.which("curl")

    setup.py, line 604

    wget = shutil.which("wget")

    setup.py, line 1121

    with urllib.request.urlopen(req, timeout=8) as r:

    Show more

    setup.py, line 1236

    with urllib.request.urlopen(req, timeout=8) as resp:

    setup.py, line 1349

    with urllib.request.urlopen(req, timeout=30) as r:

    setup.py, line 1868

    urllib.request.urlopen(url, timeout=3)

    setup.sh, line 121

    if command -v curl &> /dev/null; then

    setup.sh, line 123

    elif command -v wget &> /dev/null; then

    frontend/src/components/settings/ScaleTab.tsx, line 367

    curl http://localhost:9000/health

    synapse/cli.py, line 794

    print(f" curl -X POST http://localhost:8765/api/v1/chat \\")

  • Secrets

    Concern

    reads a credential or environment file.

    SECRETS_ENV_READ SECRETS_PATH_CREDENTIAL SECRETS_PATH_DOTENV

    setup.py, line 22

    ENV_FILE = os.path.join(ROOT_DIR, ".env")

    setup.py, line 25

    # Load .env BEFORE computing DATA_DIR so that setup.py and cli.py always

    setup.py, line 57

    CREDENTIALS_FILE = os.path.join(DATA_DIR, "credentials.json")

    Show more

    setup.py, line 29

    """Minimal .env loader -- only sets vars not already in the environment."""

    setup.py, line 59

    # Port defaults -- read from env first so an existing .env is respected

    setup.py, line 787

    # Persist the data directory path into .env so cli.py and synapse start

    setup.py, line 986

    ok(f"credentials.json already exists at {CREDENTIALS_FILE} -- skipping.")

    setup.py, line 1100

    ok(f"credentials.json saved to {CREDENTIALS_FILE}")

    backend/core/internal_auth.py, line 65

    self.token = os.getenv("SYNAPSE_INTERNAL_TOKEN", "")

    backend/core/server.py, line 384

    no_token = not os.getenv("SYNAPSE_INTERNAL_TOKEN", "")

    backend/core/user_auth.py, line 16

    s = os.getenv("SYNAPSE_JWT_SECRET", "")

    backend/core/routes/api_v2.py, line 732

    token = os.getenv("METRICS_TOKEN", "")

    backend/core/scale/config.py, line 96

    metrics_token=os.getenv("METRICS_TOKEN", settings.get("metrics_token", "")),

    backend/core/scale/config.py, line 101

    s3_access_key_id=os.getenv("S3_ACCESS_KEY_ID", settings.get("s3_access_key_id", "")),

    backend/core/scale/config.py, line 102

    s3_secret_access_key=os.getenv("S3_SECRET_ACCESS_KEY", settings.get("s3_secret_access_key", "")),

    frontend/src/proxy.ts, line 57

    const internalToken = process.env.SYNAPSE_INTERNAL_TOKEN || '';

  • Agent instructions

    Pass

    No instruction to ignore earlier instructions or to hide a step.

  • Obfuscation

    Note

    a file was over the read cap and was not fully read.

    OBFUSCATION_FILE_OVER_READ_CAP

    frontend/package-lock.json, line 1

    {

  • Licence

    Pass

    A licence file is present (LICENSE).

  • Maintainer activity

    Pass

    The latest commit is within the last 365 days.

Note

Hygiene check of commit 9ee485d09068. can delete files. install fetches a script from the network. README documents an installer that pipes a download into a shell. The docs document an installer that pipes a download into a shell. can reach a host that is not written as a fixed address. reads a credential or environment file. a file was over the read cap and was not fully read.

Date and source

Date checked:

View source

github.com

Commit graded: 9ee485d090689919397fa7f2025c6b2efd2bb170

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.

Read how this letter is chosen