How we scan
Every MCP server and skill listed here that has a README is scanned for risky commands. The scan answers one question: do the commands the README tells you, or your agent, to run ask for something dangerous?
How it works
- We read the README from GitHub and look only at command-like text: lines inside code blocks, and inline code. Sentences that merely mention a risky command are not counted.
- Each rule below is a fixed pattern. There is no model and no judgement call, so the same README always gets the same result.
- A project counts as established when it has at least 1,000 stars and is at least 180 days old. For those, a serious pattern is graded Caution instead of Unsafe, and minor ones are not held against it.
- READMEs are read again every 30 days, and grades are recomputed daily as projects gain a track record.
The results
The rules
20 rules, shown exactly as they are applied.
CriticalAlways graded Reject.
Sends secrets over the networkA command that reads credentials or environment secrets and pipes them into a network tool is how data is stolen.
Pattern · secrets-to-network
(?:cat|echo|base64)\b[^|\n]*(?:\.env\b|id_rsa|id_ed25519|\.ssh\/|\.aws\/credentials|\.npmrc|\.netrc|\.git-credentials|\bprintenv\b|\$\{?[A-Z0-9_]*(?:API_?KEY|TOKEN|SECRET|PASSWORD)\b)[^|\n]*\|[^\n]*\b(?:curl|wget|nc|ncat|netcat)\b|(?:^|[\s;&|])(?:printenv|env)\s*\|[^\n]*\b(?:curl|wget|nc|ncat|netcat)\b|\b(?:curl|wget)\b[^\n]*(?:-d|--data(?:-binary|-raw)?|-F|--post-data)[ =][^\n]*(?:\$\(\s*cat\b[^)\n]*(?:\.env\b|id_rsa|id_ed25519|\.ssh\/|\.aws\/credentials|\.npmrc|\.netrc|\.git-credentials|\bprintenv\b|\$\{?[A-Z0-9_]*(?:API_?KEY|TOKEN|SECRET|PASSWORD)\b)|@~?\/?[^\s]*(?:id_rsa|id_ed25519|\.aws\/credentials|\.env\b))Writes downloaded code into startup files or cronAppending a download to your shell startup files or crontab makes it run again and again without asking.
Pattern · payload-in-startup
\b(?:curl|wget)\b[^\n]*(?:>>?|\|\s*(?:sudo\s+)?tee\b)[^\n]*(?:\.bashrc|\.zshrc|\.bash_profile|\.zprofile|\.profile|\/etc\/profile|\/etc\/cron|crontab)|\becho\b[^\n]*\b(?:curl|wget)\b[^\n]*>>?[^\n]*(?:\.bashrc|\.zshrc|\.bash_profile|\.zprofile|\.profile|\/etc\/profile|\/etc\/cron|crontab)HighUnsafe, or Caution in an established project.
Downloads a script and runs itPiping a download into a shell runs whatever the server sends, unseen.
Pattern · pipe-to-shell
\b(?:curl|wget)\b(?![^|\n]*(?:raw\.githubusercontent\.com|astral\.sh|sh\.rustup\.rs|bun\.sh|deno\.land|get\.docker\.com|brew\.sh|install\.python-poetry\.org|get\.pnpm\.io|fnm\.vercel\.app|claude\.ai|ollama\.com|get\.helm\.sh|nodesource\.com))[^|\n]*\|\s*(?:sudo\s+)?(?:ba|z|da)?sh\b|\b(?:ba|z)?sh\s+<\(\s*(?:curl|wget)\b(?![^)\n]*(?:raw\.githubusercontent\.com|astral\.sh|sh\.rustup\.rs|bun\.sh|deno\.land|get\.docker\.com|brew\.sh|install\.python-poetry\.org|get\.pnpm\.io|fnm\.vercel\.app|claude\.ai|ollama\.com|get\.helm\.sh|nodesource\.com))|\b(?:iwr|irm|Invoke-WebRequest|Invoke-RestMethod)\b(?![^|\n]*(?:raw\.githubusercontent\.com|astral\.sh|sh\.rustup\.rs|bun\.sh|deno\.land|get\.docker\.com|brew\.sh|install\.python-poetry\.org|get\.pnpm\.io|fnm\.vercel\.app|claude\.ai|ollama\.com|get\.helm\.sh|nodesource\.com))[^|\n]*\|\s*(?:iex|Invoke-Expression)\bOpens a remote shellThese commands give someone else an interactive shell on your machine.
Pattern · reverse-shell
\/dev\/tcp\/|\b(?:nc|ncat|netcat)\b[^\n]*\s-[a-z]*e\b|\bsocat\b[^\n]*\bexec:|\bmkfifo\b[^\n]*\|\s*(?:nc|ncat)\bRuns encoded or hidden codeDecoding text and executing it hides what actually runs.
Pattern · encoded-execution
\bbase64\s+(?:-d|--decode|-D)\b[^\n]*\|\s*(?:sudo\s+)?(?:ba|z)?sh\b|\beval\s+["']?\$\([^)\n]*\bbase64\b|\bpowershell(?:\.exe)?\b[^\n]*\s-e(?:nc|ncodedcommand)?\s+[A-Za-z0-9+/=]{20,}|\bpython3?\s+-c\b[^\n]*\bexec\([^\n]*\bb64decode\bTurns off a system protectionDisabling Gatekeeper, SIP, SELinux or antivirus removes a safeguard for everything on the machine, not just this tool.
Pattern · disables-protection
\bspctl\s+--master-disable\b|\bcsrutil\s+disable\b|\bsetenforce\s+0\b|Set-MpPreference\b[^\n]*-DisableRealtimeMonitoring|\bchmod\s+(?:-R\s+)?777\s+\/(?:\s|$)Deletes or overwrites broadlyA mistyped or malicious path here can wipe a disk or a home directory.
Pattern · destructive-command
\brm\s+-[a-z]*r[a-z]*f?[a-z]*\s+(?:--no-preserve-root\s+)?(?:\/|~|\$HOME)\/?(?:\s|$|\*)|\bmkfs(?:\.\w+)?\s+\/dev\/|\bdd\b[^\n]*\bof=\/dev\/(?:sd|nvme|disk)|:\(\)\s*\{\s*:\|:&\s*\}\s*;\s*:MediumCaution.
Runs an install script from a well-known hostCommon practice for popular tools, but it still runs a script you have not read.
Pattern · pipe-to-shell-known-host
\b(?:curl|wget)\b[^|\n]*(?:raw\.githubusercontent\.com|astral\.sh|sh\.rustup\.rs|bun\.sh|deno\.land|get\.docker\.com|brew\.sh|install\.python-poetry\.org|get\.pnpm\.io|fnm\.vercel\.app|claude\.ai|ollama\.com|get\.helm\.sh|nodesource\.com)[^|\n]*\|\s*(?:sudo\s+)?(?:ba|z|da)?sh\b|\b(?:ba|z)?sh\s+<\(\s*(?:curl|wget)\b[^)\n]*(?:raw\.githubusercontent\.com|astral\.sh|sh\.rustup\.rs|bun\.sh|deno\.land|get\.docker\.com|brew\.sh|install\.python-poetry\.org|get\.pnpm\.io|fnm\.vercel\.app|claude\.ai|ollama\.com|get\.helm\.sh|nodesource\.com)|\b(?:iwr|irm)\b[^|\n]*(?:raw\.githubusercontent\.com|astral\.sh|sh\.rustup\.rs|bun\.sh|deno\.land|get\.docker\.com|brew\.sh|install\.python-poetry\.org|get\.pnpm\.io|fnm\.vercel\.app|claude\.ai|ollama\.com|get\.helm\.sh|nodesource\.com)[^|\n]*\|\s*iex\bAsks for administrator rightsWith sudo, a mistake or a compromised package can change the whole system.
Pattern · sudo
(?:^|[\s;&|(])sudo\s+\SSets itself up to run automaticallyStartup entries, services and scheduled jobs keep running after you stop paying attention.
Pattern · persistence
\|\s*crontab\b|\bcrontab\s+-e\b|\blaunchctl\s+(?:load|bootstrap)\b|\bsystemctl\s+(?:--user\s+)?enable\b|\bschtasks\s+\/create\b|CurrentVersion\\+Run\bTells the agent to skip permission promptsWithout prompts, the agent can run commands and edit files with no chance for you to say no.
Pattern · skips-agent-permissions
--dangerously-skip-permissions\b|--dangerously-bypass-approvals-and-sandbox\b|--yolo\b|--trust-all-tools\b|\bbypassPermissions\b|--allow-all-tools\bReads stored credentialsSSH keys, cloud credentials and keychains unlock far more than this tool needs.
Pattern · credential-files
\b(?:cat|cp|scp|tar|zip|base64)\b[^\n]*(?:~|\$HOME)\/(?:\.ssh\/(?![\w.-]*\.pub\b)|\.aws\/credentials|\.netrc|\.git-credentials|\.config\/gcloud)|\bsecurity\s+find-(?:generic|internet)-password\bDownloads a file and makes it executableA binary fetched outside a package manager has no signature or version check.
Pattern · downloads-and-runs-binary
\b(?:curl|wget)\b[^\n]*(?:-o|-O|--output)\b[^\n]*(?:&&|;)\s*(?:sudo\s+)?chmod\s+\+x\bGives a container access to the hostA privileged container, the Docker socket or a mount of the whole disk removes the isolation a container is for.
Pattern · container-host-access
\bdocker\b[^\n]*(?:--privileged\b|\/var\/run\/docker\.sock|-v\s+\/:\/|--pid[= ]host\b)Removes the macOS quarantine flag from an appCommon for unsigned apps, but it skips the check macOS would otherwise make before first launch.
Pattern · bypasses-gatekeeper
\bxattr\s+-[a-z]*d[a-z]*\s+com\.apple\.quarantine\bLowCaution, or ignored in an established project.
Adds a line to your shell startup fileUsually a PATH entry or an environment variable; check what the line does, since it runs in every new terminal.
Pattern · edits-shell-profile
(?:>>|\|\s*tee\s+-a)\s*~?\/?[^\s]*(?:\.bashrc|\.zshrc|\.bash_profile|\.zprofile|\.profile)\bTurns off certificate checksWithout certificate checks, a download can be swapped in transit.
Pattern · tls-verification-off
\bcurl\b[^\n]*\s(?:-k|--insecure)\b|\bwget\b[^\n]*--no-check-certificate\b|NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0|\bgit\b[^\n]*http\.sslVerify[= ]falseRuns an install script from the repositoryThe script can do anything; skim it first.
Pattern · runs-repo-script
(?:^|[\s;&|])(?:ba|z)?sh\s+(?:\.\/)?[\w./-]*(?:install|setup|bootstrap)[\w.-]*\.sh\b|(?:^|[\s;&|])\.\/[\w./-]*(?:install|setup|bootstrap)[\w.-]*\.sh\bOverrides the system package safeguardsInstalling into the system Python or as root can break other software.
Pattern · system-package-override
--break-system-packages\b|\bnpm\b[^\n]*--unsafe-perm\bInfoShown for information. Never changes the result.
Needs an API key or tokenNormal for tools that call a service. Give it the narrowest key you can.
Pattern · needs-credentials
\b[A-Z][A-Z0-9_]*(?:API_?KEY|ACCESS_TOKEN|AUTH_TOKEN|_TOKEN|_SECRET|PASSWORD)\b["']?\s*[=:]What the scan cannot tell you
- It reads the README, not the code. A project can have a harmless README and harmful code, or the other way round.
- Patterns match text, not intent. A legitimate tool that needs sudo is flagged the same as a careless one, and a README that shows an attack in order to warn about it is flagged as if it asked you to run it.
- Anything written in a way the patterns do not cover is missed. Scripts the README links to are not followed.
- This is a first filter, not a security audit. Read what you install, and run unfamiliar tools where they cannot reach your keys.
- Maintainers who think a result is wrong can tell us through the contact page; we fix the rule for everyone rather than making exceptions.