GuardX
by harshzagade
README.md
<div align="center">
# π‘οΈ GuardX
**A keyless, defensive (blue-team) code-security auditor for the [Model Context Protocol](https://modelcontextprotocol.io).**
Let your AI assistant scan codebases for secrets, audit dependencies for known CVEs, and check passwords against breach data β all from natural language.
[](https://www.python.org/)
[](https://modelcontextprotocol.io)
[](LICENSE)
[]()
[]()
[]()
</div>
---
> β οΈ **Defensive use only.** Every tool is **read-only**, **privacy-preserving**, and needs **no API keys**. Use it only on code and credentials you own or are authorized to assess.
Unlike offensive recon tools that probe live websites, this server inspects **your own code and credentials** β making it the blue-team companion to your red-team tooling.
## Table of Contents
- [Features](#features)
- [Screenshots](#screenshots)
- [Installation](#installation)
- [Connect to an MCP Client](#connect-to-an-mcp-client)
- [Usage](#usage)
- [Sample output](#sample-output)
- [How the Privacy-Safe Password Check Works](#how-the-privacy-safe-password-check-works)
- [Data sources](#data-sources)
- [Tool Reference](#tool-reference)
- [Project Structure](#project-structure)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)
## Features
- π **Secret scanning** β detect hardcoded AWS keys, GitHub/Slack tokens, private keys, JWTs, and generic credentials. Findings are **masked**, so reports are safe to share.
- π¦ **Dependency auditing** β check `requirements.txt` (PyPI), `package.json` (npm), and `go.mod` (Go modules) against the free [OSV.dev](https://osv.dev) vulnerability database.
- π **Breached-password check** β query [Have I Been Pwned](https://haveibeenpwned.com/Passwords) using **k-anonymity**; the password never leaves your machine.
- π« **No API keys, no accounts** β clone, install, run.
- π€ **Native MCP** β works with Claude Code, Claude Desktop, Gemini CLI, OpenAI Codex, Cursor, and any MCP client.
## Screenshots
### π Scan a project for hardcoded secrets
<p align="center">
<img src="assets/scan_secrets.png" alt="scan_secrets output" width="800">
</p>
### π¦ Audit dependencies against the OSV vulnerability database
<p align="center">
<img src="assets/audit_dependencies.png" alt="audit_dependencies output" width="800">
</p>
### π Check whether a password has been breached
<p align="center">
<img src="assets/check_pwned_password.png" alt="check_pwned_password output" width="800">
</p>
## Installation
```bash
git clone https://github.com/harshzagade/Guardx-mcp.git
cd Guardx-mcp
# (recommended) create a virtual environment
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate
pip install -r requirements.txt
```
**Requirements:** Python 3.10+ and the `mcp` + `httpx` packages (installed via `requirements.txt`).
## Connect to an MCP Client
GuardX runs locally over **stdio**, so any MCP-capable client can launch it. In every example below, replace `/absolute/path/to/guardx-mcp/server.py` with the real path on your machine. If you used a virtual environment, point `command` at that env's Python (e.g. `.venv/bin/python` or `.venv\Scripts\python.exe`) instead of `python`.
> π‘ First, confirm the server starts on its own (it then waits for a client on stdin β press `Ctrl+C` to exit):
> ```bash
> python server.py
> ```
<details open>
<summary><b>Claude Code</b> (CLI)</summary>
Register the server with one command:
```bash
claude mcp add guardx -- python /absolute/path/to/guardx-mcp/server.py
```
- Add `--scope project` to write it to a shared `.mcp.json` in your repo.
- Verify with `claude mcp list`, then use `/mcp` inside Claude Code.
</details>
<details>
<summary><b>Claude Desktop</b> (app)</summary>
Edit your `claude_desktop_config.json`:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"guardx": {
"command": "python",
"args": ["/absolute/path/to/guardx-mcp/server.py"]
}
}
}
```
Restart Claude Desktop; GuardX appears under the π tools menu.
</details>
<details>
<summary><b>Gemini CLI</b> (& Gemini Code Assist)</summary>
Edit `~/.gemini/settings.json` (global) or `.gemini/settings.json` (per-project). The Gemini Code Assist IDE extension reads the same file:
```json
{
"mcpServers": {
"guardx": {
"command": "python",
"args": ["/absolute/path/to/guardx-mcp/server.py"]
}
}
}
```
Then run `gemini` and use `/mcp` to confirm the server is connected.
</details>
<details>
<summary><b>OpenAI Codex</b> (CLI & IDE extension)</summary>
Codex uses **TOML** and shares config between the CLI and the IDE extension. Either run:
```bash
codex mcp add guardx -- python /absolute/path/to/guardx-mcp/server.py
```
β¦or hand-edit `~/.codex/config.toml` ( note the **underscore** in `mcp_servers`):
```toml
[mcp_servers.guardx]
command = "python"
args = ["/absolute/path/to/guardx-mcp/server.py"]
```
> Codex only supports **local stdio** MCP servers β perfect for GuardX.
</details>
<details>
<summary><b>Cursor</b> / <b>VS Code</b></summary>
Create `.cursor/mcp.json` in your project (or the global `~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"guardx": {
"command": "python",
"args": ["/absolute/path/to/guardx-mcp/server.py"]
}
}
}
```
VS Code (with MCP support) uses the same `mcpServers` shape in its settings.
</details>
> **Windows tip:** in JSON, write paths with forward slashes (`C:/Users/you/guardx-mcp/server.py`) or escaped backslashes (`C:\\Users\\you\\...`).
## Usage
Once connected, just ask your assistant in plain language:
| You say... | Tool used |
| --- | --- |
| *"Scan `./my-project` for hardcoded secrets"* | `scan_secrets` |
| *"Audit `requirements.txt` for known vulnerabilities"* | `audit_dependencies` |
| *"Has the password `password123` been pwned?"* | `check_pwned_password` |
## Sample output
Real output from running the tools (secrets shown are intentionally fake):
**`scan_secrets("demo-project")`**
```
Secret scan of demo-project
Files scanned: 1
Findings: 2 (HIGH: 2, MED: 0, LOW: 0)
Unique secrets: 2
[HIGH] AWS Access Key ID
demo-project/app.py:1
match: AKIA...LE (len 20)
[HIGH] Stripe Secret Key
demo-project/app.py:2
match: sk_l...Ab (len 33)
Note: these are heuristic matches and may include false positives. Rotate any real secret that is committed to source control.
```
**`audit_dependencies("requirements.txt")`** β with `requests==2.28.0` and `urllib3==1.26.0` pinned:
```
Dependency audit of requirements.txt
Ecosystem: PyPI
Dependencies checked: 2
Vulnerable packages: 2
[!] requests==2.28.0 -> 8 known vuln(s)
- GHSA-9hjg-9r4m-mvj7 (CVE-2024-47081, PYSEC-2026-1872): Requests vulnerable to .netrc credentials leak via malicious URLs
- GHSA-9wx4-h78v-vm56 (CVE-2024-35195, PYSEC-2026-1873): Requests `Session` object does not verify requests after making first request with verify=False
- GHSA-gc5v-m9x4-r6x2 (CVE-2026-25645, PYSEC-2026-2275): Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility function
...
[!] urllib3==1.26.0 -> 24 known vuln(s)
- GHSA-2xpw-w6gg-jr37 (CVE-2025-66471, PYSEC-2026-1994): urllib3 streaming API improperly handles highly compressed data
...
```
**`check_pwned_password("password123")`**
```
WARNING: this password has appeared in known breaches 2,266,543 times. [!]
Do not use it. Choose a unique, strong password and enable MFA.
(Only the SHA-1 prefix was sent; the password never left this machine.)
```
A password not found in any breach returns `Good news: this password was NOT found in any known breach. [OK]`.
## How the Privacy-Safe Password Check Works
`check_pwned_password` follows the [k-anonymity model](https://haveibeenpwned.com/API/v3#PwnedPasswords) recommended by Have I Been Pwned:
1. The password is hashed locally with **SHA-1**.
2. Only the **first 5 hex characters** of the hash are sent to the HIBP range API.
3. The API returns all hash suffixes sharing that prefix; the match is found **locally**.
4. The request sends `Add-Padding: true`, so every response is padded to the
same size β a network observer cannot infer which prefix you looked up
from the response length.
β‘οΈ Your password and its full hash **never leave your machine**.
## Data sources
- **Vulnerabilities:** `audit_dependencies` queries the [OSV.dev](https://osv.dev) API **live on every run** β there is no local vulnerability database to download or refresh, so results reflect the latest published advisories at query time. Each query sends only `{package name, version, ecosystem}`. Freshness caveat: advisories appear in OSV as it ingests them from upstream sources (NVD, GitHub Security Advisories, PyPA, β¦), so a brand-new CVE may take a little while to show up. Internet access is required; lookups that fail (network error or non-200 response) are reported in the output rather than silently dropped.
- **Breached passwords:** `check_pwned_password` uses the [Have I Been Pwned Pwned Passwords API](https://haveibeenpwned.com/API/v3#PwnedPasswords) with k-anonymity (see above). Internet access is required. The breach corpus is maintained by HIBP and refreshed as new breaches are added β the breach counts you see reflect the corpus at query time, not a fixed snapshot.
## Tool Reference
| Tool | Signature | Description |
| --- | --- | --- |
| **Secret scanner** | `scan_secrets(path, max_findings=200, exclude=None, json_output=False)` | Recursively scans a file or directory for hardcoded secrets. Skips binaries and common ignore dirs (`.git`, `node_modules`, β¦), and honours a `.gitignore` at the scan root (basename patterns at any depth, root-anchored patterns, trailing-slash dir patterns, `!` negations β last match wins). A comma-separated `exclude` glob list (e.g. `"*.min.js,fixtures/*"`) skips extra noisy paths on top. Long minified lines are scanned in overlapping windows instead of being skipped. Findings are graded HIGH/MED/LOW and the report header carries per-severity counts plus a "Unique secrets" count β the number of distinct secret values across the whole scan, so one key committed in twelve files shows as one unique secret. With `json_output=True` the report is returned as machine-readable JSON (file, line, type, severity, masked match per finding) for CI pipelines. Values are masked so reports are safe to share. |
| **Dependency auditor** | `audit_dependencies(path)` | Parses a `requirements.txt`, `package.json`, or `go.mod` and checks each pinned dependency against OSV.dev. Returns CVE/GHSA ids and summaries. |
| **Pwned-password check** | `check_pwned_password(password)` | Checks a password against HIBP via k-anonymity. Reports breach count without transmitting the password. Retries twice with jittered backoff on transient network failures. |
## Project Structure
```
guardx-mcp/
βββ server.py # MCP server + the three tools
βββ tests/ # pytest suite (stdlib-only, no extra installs)
β βββ test_scan_secrets.py
β βββ test_pwned_password.py
β βββ test_gitignore.py
βββ requirements.txt # runtime dependencies (mcp, httpx)
βββ assets/ # README screenshots
βββ README.md
βββ CHANGELOG.md
βββ LICENSE # MIT
βββ .gitignore
```
## Troubleshooting
- **`ModuleNotFoundError: No module named 'mcp.server.fastmcp'`** β you installed `mcp` 2.x, which renamed `FastMCP` to `MCPServer`. GuardX targets the 1.x SDK, so pin it in your venv:
```bash
pip install "mcp<2" httpx
```
- **`audit_dependencies` / `check_pwned_password` report network failures** β both tools need internet access (OSV.dev and Have I Been Pwned respectively). Corporate proxies may need to be configured in your environment.
## Contributing
Contributions are welcome! Ideas: more secret patterns, additional ecosystems
(Cargo, Maven), or an SBOM export. Please keep all contributions
**defensive** in nature. Open an issue or a pull request.
## License
Released under the [MIT License](LICENSE).
---
<div align="center">
<sub>Built as a defensive blue-team companion. Scan responsibly. π‘οΈ</sub>
</div>
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues