CIPHER MCP Scan
Version 0.4 adds industrial finding metadata, richer CLI output, precision fixes, and a gating GitHub Actions workflow while preserving the five static checks and optional remote_oauth behavior.
CIPHER is a local static scan for MCP-oriented codebases. It inspects a checked-out project locally and runs five focused static checks: authentication, over-privilege, CVE lookup, typosquatting, and tool poisoning.
The tool_poisoning check examines MCP JSON tool metadata for instruction overrides, data-exfiltration requests, dangerous URI schemes, and hidden Unicode control characters. It is always included with the four static checks; remote_oauth remains separate and opt-in through --remote-url.
Findings include stable rule_id, detection_method, evidence, confidence, remediation, line ranges, and owasp_tags. The scanner remains static and deterministic by default; remote OAuth is the only opt-in active probe.
Modular API reports
The FastAPI service stores successful scan reports in reports/ beside modular_api.py by default. Set REPORTS_DIR to use a different directory. Existing reports from the legacy .cipher_reports/ location are not read automatically; move any files to reports/ once if they need to remain available.
On Render, set REPORTS_DIR to the mount path when using a persistent disk. Without a Render persistent disk, report files are ephemeral and do not survive redeploys. This API storage is separate from the CLI's local --output option.
Optional remote OAuth check
The fifth check is opt-in and runs only when an explicit remote URL is supplied. It probes OAuth well-known metadata, dynamic client registration, and a small set of redirect URI validation cases. It does not run during the normal cipher-scan . workflow or standard CI scans.
cipher-scan ./my-application --remote-url https://example.test/mcp --fail-on high
Remote connection failures are reported as low-severity transport results so static findings and the scan report are preserved. Only accepted dangerous redirect schemes produce high-severity remote findings. Use this check only against systems you are authorized to test; it is intended for lab and explicitly approved environments.
The remote OAuth probe is adapted from the concepts and minimal active probes in remote-mcp-scanner, copyright Nova Security, licensed under the MIT License. The reference project is not imported as a runtime dependency.
Prior art / related tools
CIPHER's deterministic metadata rules were informed by invariantlabs-ai/mcp-scan, yatuk/mcpradar, sahiloj/MCPScan, alexandriashai/mcp-guardian, and bryand410/mcp-scrutiny. OAuth probe concepts were compared with novasecuritynz/remote-mcp-scanner. No vendor source is bundled or required.
Install
pip install cipher-mcp-scan
Use CIPHER directly in the CLI
- Install:
pip install cipher-mcp-scan
- Check it works:
cipher-scan --help - Scan the current directory:
cipher-scan . --fail-on high
- Scan a specific project path:
cipher-scan path/to/project --fail-on high
- Report only without failing CI:
cipher-scan . --fail-on none
- Write a JSON report:
cipher-scan . --fail-on high --format json --output cipher-report.json
- Exit codes:
0= scan completed and policy is satisfied1= findings are at or above the selected threshold2= tool error, invalid path, or optional CVE hard-fail
--fail-onvalues:criticalhighmediumnone
Use CIPHER in GitHub Actions
The repository includes .github/workflows/cipher-scan.yml.
It installs CIPHER locally, runs the human gate at --fail-on high, writes a JSON report,
and uploads that report as an artifact. The default job is gating: exit code 1 blocks the
workflow. No secrets are required for the static scan.
Add a workflow in your project under .github/workflows/ and run the scanner after checkout. This works for public and private repos because the scan is local to the checked-out code.
Point to the demo file in this repo at examples/github-actions-cipher-scan.yml. You can copy that file into your repo as .github/workflows/cipher-scan.yml, or paste the workflow block below.
name: CIPHER MCP Scan
on:
pull_request:
push:
branches:
- main
- master
workflow_dispatch:
jobs:
cipher-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install CIPHER
run: |
python -m pip install --upgrade pip
pip install cipher-mcp-scan
- name: Run CIPHER scan
env:
GITHUB_STEP_SUMMARY: ${{ github.step_summary }}
run: |
cipher-scan . --fail-on high --summary github --output cipher-scan-report.json
- name: Upload JSON report
if: always()
uses: actions/upload-artifact@v4
with:
name: cipher-scan-report
path: cipher-scan-report.json
if-no-files-found: ignore
To use it in another repo:
- Copy examples/github-actions-cipher-scan.yml to
.github/workflows/cipher-scan.yml - Or paste the block above into that file
- Open a PR or push to
main/masterto trigger the check
Optional flags
--summary githubwrites a markdown summary to the Actions job summary when available--format text|jsonchanges the output style--jsonemits machine-readable JSON only--verboseprints full evidence and detection metadata--by-checkgroups human findings by check--no-colordisables ANSI color--cve-fail-on-errormakes OSV infrastructure failures return exit code2--output REPORT.jsonsaves the machine-readable report
The scanner is static evidence for human review, not proof of exploitability. It can produce false positives or miss runtime behavior. CVE results depend on OSV availability. Review findings before acting on them, and do not send private source code to an untrusted third-party host without reviewing the deployment and data-handling risks.
For the optional pytest suite, install the pinned-compatible test tools with
pip install -e ".[test]". The repository's unittest self-tests do not require pytest.
Modular API quick check
curl -sS https://<your-render-host>/health
curl -sS -X POST https://<your-render-host>/modularscan \
-H "Content-Type: application/json" \
-d '{"repo_url":"https://github.com/<owner>/<repo>"}'
The default API request runs the five static checks in fixed order. remote_url is optional
and enables the remote OAuth probe only when explicitly supplied. The API is intended for
authorized deployments; review network exposure and authentication before using it with private
code.
Short note
v0.1 is limited to the built-in CIPHER checks. Optional third-party compare engines are future work and are not required for this package.
Longer internal notes are preserved in README_ARCHIVE.md.
CLI UX
The command-line tool has a short banner on --help / -h and no noisy startup banner on successful scans. Example help output includes the package name, version, example commands, and a one-line fail-on explanation.
Local verification
Run these locally without uploading anything:
pip install -e .
cipher-scan --help
cipher-scan ./test/Cipher-demo-main --fail-on high
The demo path is useful for a quick smoke test because it includes intentionally vulnerable MCP sample code.
Production smoke test
After a Render deploy, run these three requests in order:
curl -sS https://<your-render-host>/healthand verifystatusisok.curl -sS -X POST https://<your-render-host>/modularscan -H "Content-Type: application/json" -d '{"repo_url":"https://github.com/<owner>/<repo>"}'and verify the five static checks remain inchecks_run, with groupedresultsand the additive normalizedfindingsenvelope.- Repeat step 2 with
,"remote_url":"http://127.0.0.1:9"added to the JSON body. Verify the response remainsstatus: "ok", includesremote_oauth, and records a low-severity transport finding without affecting static results.
Clients should poll /health before the first scan to accommodate Render cold starts.
Metadata
Release files for cipher-mcp-scan 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cipher_mcp_scan-0.4.0.tar.gz | 64.3 kB | Without provenance | Details for cipher_mcp_scan-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cipher_mcp_scan-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for cipher_mcp_scan-0.4.0-py3-none-any.whl |
Total release size: 128.7 kB
Release files / cipher_mcp_scan-0.4.0.tar.gz
| Download URL | cipher_mcp_scan-0.4.0.tar.gz |
|---|---|
| Size | 64.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9c8ba4c77f50998903ec2b20f081c62f516971f8c5bd72f381f300fecce6c9bd
|
|
BLAKE2b-256 checksum How to use checksums |
45f6a8ac0b17ff508927966d6c38956c8551af4f387d7e8b3b29cc6fde2aeab5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|
Release files / cipher_mcp_scan-0.4.0-py3-none-any.whl
| Download URL | cipher_mcp_scan-0.4.0-py3-none-any.whl |
|---|---|
| Size | 64.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2b68e390218d5ab01ffa97e1ff34d44966ec22f713ce833e8fcaac9a50beb3fd
|
|
BLAKE2b-256 checksum How to use checksums |
5a8bde1f0e6ab7aee8a0d1a8aa2957ef8a0809b6c9e61ff9c19fe8ba63d17274
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|
Security for cipher-mcp-scan 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.