Skip to main content
← All rules

mcp-scan rule

Python inline execution

python-inline-executioncritical

What mcp-scan saw

The AST scanner joined the command with its args and matched python (optionally versioned, python3) followed later by -c and then by exec( or eval(. All three parts must appear in that order in the same joined string for the rule to fire.

Why it fires

Code passed through -c never lands on disk, so nothing reviews it: not your editor, not code review, not a file-integrity check. Wrapping it in exec() or eval() adds a second layer where the executed string can itself be assembled from an env var at runtime, which means the audited config and the executed code are different things.

When this is a false positive

  • The three parts are matched independently with .* between them, so a python server that takes an unrelated -c config flag and separately documents an eval( example in an argument satisfies the pattern without any inline execution.
  • A wrapper that passes a user-facing expression evaluator through, for example a calculator server whose args carry eval( as literal help text.
  • Only python is matched. The same inline execution through uv run -c, pipx run, or a shell wrapper does not fire this rule, so a clean report here is not proof the server has no inline execution.

How to fix it

  1. Read the full command from the finding text and find the -c payload.
  2. Move that payload into a real .py file next to the config, and change the args to point at the file path instead of -c.
  3. Remove exec( and eval( from the payload. If the code is assembling a call from a string, replace it with a dispatch dict keyed on the allowed operation names.
  4. Re-scan. The rule needs all three of python, -c, and exec/eval, so moving the code to a file clears it.
  5. If the -c flag belongs to the server and is not Python's, rename the flag or reorder the args so it does not sit between python and an eval( literal.