← All MCP servers
MCP server

io.snyk/mcp

mcp:snyk/studio-mcp

Easily find and fix security issues in your applications leveraging Snyk platform capabilities.

Verdict
Suspicious

Risky behavior the analysis could not rule out.

Analyzed Oct 26, 2026, 12:13 UTC at b4285af
3
findings
high
highest severity
2
threat classes
233
files scanned
1,179/1,179
checks satisfied
0
package advisories

Why this verdict

  • suspicious: finding mcp-server:.:internal/configure/configure.go:260:SUPPLY
  • suspicious: finding mcp-server:.:internal/configure/configure.go:261:SUPPLY
  • suspicious: finding mcp-server:.:internal/mcp/tools.go:219:CRED

Security findings 3

Credential access

highContextual risklow confidence

At trace log level, runSnyk logs the full environment passed to the Snyk CLI subprocess, which can include injected auth tokens, to the log file, stderr and MCP client notifications; this is undeclared and only partly mitigated by an empty scrubbing dictionary.

logger.Trace().Strs("env", command.Env).Msg("Environment")
vector:code
Counter-argument considered

At trace level the full subprocess environment is logged, and that environment can include injected Snyk auth tokens. No redaction is shown in this code path.

Supply chain

mediumContextual risklow confidence

The configure feature registers an MCP server entry in host config that runs unpinned remote code via `npx -y snyk@latest`, so every host launch fetches whatever the latest published version is.

return "npx", []string{"-y", "snyk@latest", "mcp", "-t", "stdio"}
vector:code
Counter-argument considered

Host config is written to launch 'npx -y snyk@latest', an unpinned remote package fetched on every host start when run from npm. No pin or mitigation is shown.

Supply chain

mediumContextual risklow confidence

When run from npm, the MCP server entry written to host config launches an unpinned remote package via npx -y snyk@latest, so future executions fetch whatever the registry serves.

return "npx", []string{"-y", "snyk@latest", "mcp", "-t", "stdio"}
vector:code
Counter-argument considered

Same unpinned npx -y snyk@latest launch command is written to the host MCP config; nothing pins the version.

Open questions 1

What the analysis could not settle from the code alone.

[file request internal/configure/mcp_config.go] What does getSnykMcpEnv put into the MCP config env (credentials/tokens?) and how does ensureMcpServerInJson write it?
Credential access
Refuted findings 11

Candidates the review stage examined and rejected, kept for transparency.

Persistence

criticalRefutedlow confidence

The configure feature writes MCP server entries and always-applied rules/skills files into agent control-plane locations (global rules for Windsurf, gemini-cli, claude-cli, MCP host configs), which is a persistent agent-config write; it appears to be the product's declared IDE integration purpose but is a control-plane capability.

// Write global rules with delimiters (e.g. Windsurf, Antigravity, gemini-cli, claude-cli)
Why it was refuted

The configure feature is the tool's self-described core function, user-invoked and with visible output. Writing MCP entries and rules into IDE host configs is the declared core capability, not concealed.

Persistence

criticalRefutedlow confidence

The configure feature writes a Snyk rules block into the Antigravity global agent rules file ~/.gemini/GEMINI.md. This is an undeclared agent control-plane write, though it is visible, delimited and user-invoked.

globalRulesPath:      filepath.Join(homeDir, ".gemini", "GEMINI.md"),
Why it was refuted

The Antigravity host path is part of the self-described configure feature for IDE hosts. It writes a delimited, user-invoked block, which is the declared core capability.

Persistence

criticalRefutedlow confidence

The configure feature for gemini-cli writes persistent rules into ~/.gemini/GEMINI.md, which is loaded into every agent session. This is an undeclared agent memory/rules write, though it is visible and delimited.

globalRulesPath:     filepath.Join(homeDir, ".gemini", "GEMINI.md"),
Why it was refuted

The gemini-cli entry is the configure feature's intended host target, with delimited and visible writes. It is declared core capability.

Persistence

criticalRefutedlow confidence

The configure feature for claude-cli modifies the agent MCP configuration ~/.claude.json to register the Snyk MCP server, preserving other entries. This is an undeclared agent control-plane write, though it is the visible purpose of the configure command.

mcpGlobalConfigPath: filepath.Join(homeDir, ".claude.json"),
Why it was refuted

Registering the Snyk MCP server in ~/.claude.json for claude-cli is the visible purpose of configure. The write preserves other entries and is user-invoked, so it is declared core capability.

Persistence

criticalRefutedmedium confidence

The configure command writes the Snyk MCP server entry and embedded rules into agent control-plane files (~/.claude.json, ~/.claude/CLAUDE.md, ~/.gemini/GEMINI.md, ~/.cursor/mcp.json) outside the workspace, giving persistent influence over the agent. This matches the declared IDE-configure purpose and is not hidden.

filepath.Join(homeDir, ".claude", "CLAUDE.md")
Why it was refuted

Writing delimited Snyk rules into CLAUDE.md and the MCP config is the declared function of configure. It is user-invoked and announced, not concealed.

Persistence

criticalRefutedlow confidence

The configure code writes or updates MCP server entries in IDE/agent JSON config files (agent control-plane persistence), and this is the tool's declared setup purpose.

ensureMcpServerInJson creates or updates MCP server configuration in a JSON file
Why it was refuted

The code merges the Snyk MCP entry into IDE JSON config while preserving other fields. This is the documented setup purpose of the configure feature.

Persistence

criticalRefutedlow confidence

The configure code writes rules and skills files into global agent locations, and the bundled rule templates are marked always-apply, so persistent agent instructions are installed outside the workspace.

writeGlobalRules writes rules to a global location with delimited markers
Why it was refuted

Writing delimited global rules and skills is the configure feature's declared function. It uses clear markers and supports removal, so it is not concealed.

Persistence

criticalRefutedlow confidence

The configure feature installs a rules file with alwaysApply/always_on triggers matching all files, so the Snyk security rule is loaded into the agent's context on every task; this is the tool's declared purpose, but it is a persistent agent control-plane write.

alwaysApply: true
Why it was refuted

The alwaysApply rule is the product's own embedded rule template, installed by the declared configure feature. Its content simply asks the agent to run the Snyk scan on new code.

Supply chain

criticalRefutedmedium confidence

The Makefile 'tools' target fetches the golangci-lint install script from raw.githubusercontent.com and pipes it to sh; the script is pinned by tag, but it is remote code outside the pinned commit and runs as a dev-time build step.

curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/$(OVERRIDE_GOCI_LINT_V)/install.sh | sh -s -- -b $(TOOLS_BIN)/ $(OVERRIDE_GOCI_LINT_V)
Why it was refuted

Dev-time 'tools' target that fetches the vendor's own golangci-lint installer, pinned to an explicit version tag through the same variable passed as the installer argument. This is a pinned vendor-installer pattern with no runtime or agent-facing effect.

Supply chain

highRefutedlow confidence

A vendored CI workflow downloads the latest libpathrs release tarball from a mutable source, builds it, and installs it with sudo; it is in a third-party license directory and is likely not executed.

sudo ./install.sh --libdir=/usr/lib
Why it was refuted

The file sits under the generated licenses directory, which the Makefile produces by running go-licenses save. It is an inert copy of a dependency's upstream CI workflow, not invoked by any build or agent step, so there is no source-to-sink chain.

Privilege escalation

mediumRefutedlow confidence

An undeclared vendored third-party dev test script (filepath-securejoin hack/test.sh, in the licenses directory) runs the Go tests under sudo; it is unexplained by the MCP server's purpose, but it is an upstream test helper not wired into the build.

sudo "$GO" test "${test_args[@]}" ./... -args -test.gocoverdir="$gocoverdir"
Why it was refuted

This is an upstream dependency test helper copied into the generated licenses directory by go-licenses save. Nothing in the build invokes it, so there is no chain to execution.

Coverage gaps 75

Parts of the artifact the static analysis could not fully examine.

no_dataflow_for_go go file: string-literal extraction only
internal/analytics/analytics.go
no_dataflow_for_go go file: string-literal extraction only
internal/apiclients/breakability/2025-11-05/breakability.go
no_dataflow_for_go go file: string-literal extraction only
internal/apiclients/breakability/2025-11-05/gen.go
no_dataflow_for_go go file: string-literal extraction only
internal/apiclients/package/2024-10-15/gen.go
no_dataflow_for_go go file: string-literal extraction only
internal/apiclients/package/2024-10-15/package_info.go
no_dataflow_for_go go file: string-literal extraction only
internal/authentication/authentication_functions.go
no_dataflow_for_go go file: string-literal extraction only
internal/breakability/breakability_api.go
no_dataflow_for_go go file: string-literal extraction only
internal/code/map.go
no_dataflow_for_go go file: string-literal extraction only
internal/configure/configure.go
no_dataflow_for_go go file: string-literal extraction only
internal/configure/env.go
no_dataflow_for_go go file: string-literal extraction only
internal/configure/host_config.go
no_dataflow_for_go go file: string-literal extraction only
internal/configure/mcp_server.go
no_dataflow_for_go go file: string-literal extraction only
internal/configure/rules.go
no_dataflow_for_go go file: string-literal extraction only
internal/configure/utils.go
no_dataflow_for_go go file: string-literal extraction only
internal/logging/logger.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/api.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/llm_binding.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/options.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/profiles.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/scan_response_mapper.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/tools.go
no_dataflow_for_go go file: string-literal extraction only
internal/mcp/utils.go
no_dataflow_for_go go file: string-literal extraction only
internal/networking/networking.go
no_dataflow_for_go go file: string-literal extraction only
internal/oss/map.go
no_dataflow_for_go go file: string-literal extraction only
internal/oss/scan_result.go
no_dataflow_for_go go file: string-literal extraction only
internal/package_health/package_api.go
no_dataflow_for_go go file: string-literal extraction only
internal/trust/trust.go
no_dataflow_for_go go file: string-literal extraction only
internal/types/types.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/doc.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/internal/consts/consts.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/internal/testutils/iface.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/internal/testutils/os.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/join.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/assert/assert.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/errors_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/at_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/fd.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/fd_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/mount_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/doc.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_errors_go120.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_errors_unsupported.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_generics_go121.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_generics_unsupported.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/doc.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/mkdir_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/open_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/kernelversion/kernel_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/doc.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/mount_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs/procfs_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs/procfs_lookup_linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/testutils/iface.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/testutils/linux.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/testutils/os.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_libpathrs.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_purego.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/open.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/open_purego.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_libpathrs.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_purego.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/cyphar/filepath-securejoin/vfs.go
no_dataflow_for_go go file: string-literal extraction only
licenses/github.com/hashicorp/go-uuid/uuid.go
no_dataflow_for_go go file: string-literal extraction only
pkg/mcp/main.go
no_dataflow_for_go go file: string-literal extraction only
shared/types.go
no_tools_extracted MCP server target with no statically extractable tools/prompts/resources
go.mod