Skip to main content
← All rules

mcp-scan rule

Shell injection risk

shell-injection-riskcritical

What mcp-scan saw

The config scanner walked each string argument and split it three ways: $(...) or backtick pairs are command substitution and push CRITICAL; a ${...} expression that is not exactly ${NAME} pushes MEDIUM; a plain ${NAME} in any case is allowed and pushes nothing.

Why it fires

Nothing in an MCP args array is shell-expanded. The client hands the array to the process directly, so $(whoami) stays four literal words unless something downstream re-shells it. That means command substitution in a config is either dead text or a payload aimed at a wrapper that does re-shell, and the second case is why it is CRITICAL rather than a style note.

When this is a false positive

  • The backtick shape is /`.*`/ on the whole argument, so any argument carrying two backticks matches. A --system-prompt or --instructions argument with a markdown code span fires CRITICAL with no substitution present.
  • Some launchers and shell wrappers do expand these before handing off, which makes $(...) intentional. It is still a live injection point, so this is a case to document rather than dismiss.
  • The MEDIUM variant fires on ${BASE}/api, which is a normal way to compose a URL from a prefix. It is a config smell only because the client will not expand it, so the server receives the literal braces.

How to fix it

  1. Read the argument quoted in the finding text and decide which of the two shapes it is.
  2. For the CRITICAL shape, delete the substitution. If you need a computed value, compute it before launch and pass the result as a literal or through env.
  3. For the MEDIUM shape, replace ${BASE}/api with a fully resolved literal, or split it into two arguments where the variable stands alone as ${BASE}.
  4. If the backticks are prose in a prompt argument, replace them with quotes so the argument stops matching.
  5. If a wrapper genuinely expands your arguments, remove the wrapper. Passing untrusted config text through a shell is the underlying problem the rule is pointing at.