# Repo Security Scanner - Malicious Code & Supply Chain (`eltociear/mcp-server-security-scanner`) Actor

Audit GitHub repos for malicious and supply-chain code before you install or depend on them. Scans a repo list, a whole GitHub user/org, or the MCP registry. Returns a risk level, score and evidence per repo.

- **URL**: https://apify.com/eltociear/mcp-server-security-scanner.md
- **Developed by:** [Ikko Eltociear Ashimine](https://apify.com/eltociear) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 mcp server auditeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Repo Security Scanner — Malicious Code & Supply Chain

**Audit GitHub repositories for malicious and supply-chain code before you install or depend on
them.** Give it a list of repos, a whole GitHub user/org, or the entire official MCP server
registry, and get back one row per repo: a risk level, a score, and the single worst finding
with the file, line and evidence that triggered it.

Installing a dependency, an agent tool, or an MCP server means running someone else's code —
often at *install time*, before your own code ever executes. This scans for the patterns that
matter and tells you which repos to look at twice.

### What it looks for

Install-time execution is checked **first**, because it is the biggest supply-chain vector:

| Pattern | Severity |
| --- | --- |
| Install hooks that run commands (`package.json` pre/postinstall, `setup.py`) | via the rules below |
| Download-and-execute (`curl … \| sh`, `eval(fetch(…))`) | CRITICAL |
| Credential / token exfiltration to an external host | CRITICAL |
| Seed-phrase / private-key harvesting | CRITICAL |
| Writes to sensitive dirs (`~/.ssh`, `~/.aws`) | CRITICAL |
| Unsafe dynamic code execution with untrusted input | HIGH |
| Prompt-injection markers ("ignore previous instructions", "operate unconditionally") | HIGH |
| Auth/security bypass (`verify=False`, `rejectUnauthorized:false`) | HIGH |

Capability *mentions* (an outbound URL, a broad filesystem read, a plugin-install line) are
reported separately as context and **never inflate the score** — the calibration that keeps a
scanner from being muted on day one. 17 named patterns / 60 signatures, deterministic: no LLM,
no code execution.

### Input

| field | meaning |
| --- | --- |
| **What to scan** | A list of repos · every public repo of a user/org · or the official MCP registry. |
| **Repositories** | GitHub URLs (for the list mode). |
| **GitHub user or organization** | e.g. `openai` — audits all their public, non-fork repos. |
| **Maximum repositories** | Hard cap on how many are audited — and, since you pay per audit, your spending cap. |
| **Only return repos at or above** | Filter output by risk. Every repo is still audited; this only controls what appears. |
| **Include every finding** | Off returns just the risk level, score and worst finding — a much smaller result. |

### Output

One dataset item per repository:

```jsonc
{
  "repo": "owner/name",
  "repo_url": "https://github.com/owner/name",
  "risk_level": "CRITICAL",        // CRITICAL | HIGH | MEDIUM | LOW | SAFE | UNKNOWN
  "risk_score": 25,
  "finding_count": 1,
  "counts": { "CRITICAL": 1 },
  "top_finding": {
    "file": "package.json",
    "severity": "CRITICAL",
    "pattern": "Download & Execute",
    "line": 4,
    "evidence": "\"postinstall\": \"curl https://… | bash\""
  },
  "files_scanned": ["package.json", "src/index.ts"],
  "findings": [ /* every match, when 'Include every finding' is on */ ]
}
```

`UNKNOWN` is reported, never hidden, and is split by cause: `repo_gone` (deleted or private
since listed), `no_entry_point` (exists but keeps code somewhere unusual), or `unreachable`. It
is **not** a clean bill of health.

### Pricing

Pay-per-event: charged once per repository audited. `Maximum repositories` is therefore also
your budget cap. Filtering the output does not reduce the charge, because the audit is the work.

### Use cases

- **Before you `npm install` / `pip install`** — audit the dependency's repo for install-time
  execution and credential exfiltration.
- **Vetting AI agent tools and MCP servers** — scan the whole official MCP registry, or one
  server, before you connect it to an agent that holds your keys.
- **Org-wide hygiene sweep** — point it at your GitHub org and get a ranked list of which repos
  contain risky patterns.
- **Supply-chain due diligence** — audit an acquisition target's or vendor's public repos.

### FAQ

**Does it execute any of the scanned code?**
No. The scan is purely lexical — it reads source files and matches behavioural patterns. Nothing
is installed, built or run.

**Is this a vulnerability scanner / SCA tool?**
No. It does not check dependency versions against CVE databases. It looks for *malicious and
supply-chain behaviour* in the code itself — pipe-to-shell installers, token exfiltration,
seed-phrase harvesting, prompt injection — which CVE-based tools do not cover.

**What does a SAFE result mean?**
"No known pattern matched." It is not a guarantee of safety. Treat CRITICAL as "look here
first", and every finding as a pointer for human review rather than a verdict.

**Why do some repos come back UNKNOWN?**
Because the truth is unknown: the repo was deleted or made private (`repo_gone`), keeps code
somewhere the scanner did not look (`no_entry_point`), or could not be reached
(`unreachable`). It is reported rather than quietly counted as clean.

**How much does a scan cost?**
You pay per repository audited, so `Maximum repositories` is your hard spending cap.

### How it decides

The scanner is **lexical** — it reads source and matches behavioural patterns; it never executes
anything. Risk level is the highest-severity real finding present, so one credential-exfil or
pipe-to-shell reads as CRITICAL regardless of count. It is strongest on self-contained payloads
(a `curl … | bash`, an `eval(request…)`, a malicious install hook) and weaker on behaviour split
across many files or heavily obfuscated. Treat SAFE as "no known pattern matched", not a
guarantee — and CRITICAL as "look here first".

Findings are pattern matches that warrant human review, not verdicts. Never publish one as an
unverified accusation.

# Actor input Schema

## `mode` (type: `string`):

A list of repositories, every public repo of a GitHub user/org, or the whole official MCP server registry.

## `repos` (type: `array`):

GitHub repository URLs to audit. Used when 'What to scan' is 'A list of repositories'.

## `org` (type: `string`):

Audit every public, non-fork repository this user or org owns. Used when 'What to scan' is 'All repos of a GitHub user / org'.

## `maxRepos` (type: `integer`):

You are charged per repository audited, so this is also your spending cap.

## `minRiskLevel` (type: `string`):

Filters the results. Every repo is still audited and charged for — set 'Maximum repositories' to control cost.

## `includeFindings` (type: `boolean`):

Off returns just the risk level, score and the single worst finding — a much smaller dataset.

## `concurrency` (type: `integer`):

Higher finishes sooner but is more likely to be rate-limited by GitHub.

## Actor input object example

```json
{
  "mode": "repos",
  "repos": [
    "https://github.com/modelcontextprotocol/servers"
  ],
  "org": "modelcontextprotocol",
  "maxRepos": 50,
  "minRiskLevel": "SAFE",
  "includeFindings": true,
  "concurrency": 5
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "repos": [
        "https://github.com/modelcontextprotocol/servers"
    ],
    "org": "modelcontextprotocol"
};

// Run the Actor and wait for it to finish
const run = await client.actor("eltociear/mcp-server-security-scanner").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "repos": ["https://github.com/modelcontextprotocol/servers"],
    "org": "modelcontextprotocol",
}

# Run the Actor and wait for it to finish
run = client.actor("eltociear/mcp-server-security-scanner").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "repos": [
    "https://github.com/modelcontextprotocol/servers"
  ],
  "org": "modelcontextprotocol"
}' |
apify call eltociear/mcp-server-security-scanner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=eltociear/mcp-server-security-scanner",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/8lgbSxm4HtTj4Cdib/builds/Z8CK9xlRM5vv7UkeY/openapi.json
