A security audit MCP server for Laravel projects — built with TypeScript and stdio transport.
Laraguard MCP is a standalone Model Context Protocol (MCP) server that performs security audits on Laravel projects. It is implemented in pure TypeScript using the official @modelcontextprotocol/sdk and communicates over stdio, making it natively compatible with any MCP-capable IDE or client (Cursor, Claude Desktop, VS Code MCP extensions, etc.).
The server analyses a Laravel project as an external target — it does not require Laravel to be running. It returns structured JSON findings categorised by severity, covering configuration issues, risky code patterns, and dependency hygiene.
- 🔍 Static code scanning — 15+ rules covering SQL injection, RCE, hardcoded credentials, weak crypto, mass assignment, and LFI
- 🎭 Blade XSS scanner — detects unescaped
{!! !!}output and raw input rendering in templates - 🛣️ Route & middleware audit — flags admin routes without auth, API routes without auth:sanctum, login routes without throttle, and CSRF exceptions
- 📦 Dependency CVE feed — queries the OSV.dev API for real CVEs across all
composer.lockpackages - ⚙️ Configuration audit — inspects
.env(DEBUG, APP_KEY, APP_ENV, secure cookies) andconfig/cors.php - 🗂️ Project metadata — reads
composer.jsonto identify Laravel and PHP version constraints - 💥 Active attack simulation — fires HTTP probes (SQL injection, XSS, CSRF, auth bypass, rate limiting) against a running app
- 🔒 Path traversal prevention — strict allowlist enforcement for all file operations
- ✂️ Secret redaction — sensitive values are masked in textual output before reaching the MCP client
- 🚀 stdio transport — zero-config network; works inside any IDE that supports MCP
The server exposes 8 tools. All static tools accept a single path parameter. attack_simulate additionally requires a baseUrl.
| Tool | Input | Description |
|---|---|---|
project_info |
path |
Returns metadata from composer.json: project name, Laravel/PHP version constraints, engine info. |
dependency_audit |
path |
Parses composer.lock and queries OSV.dev for real CVEs with severity and fix versions. |
config_audit |
path |
Inspects .env (DEBUG, APP_KEY, APP_ENV, session cookies) and config/cors.php (wildcard origins). |
code_scan |
path |
15+ static pattern rules across all PHP files — credentials, weak crypto, mass assignment, RCE, LFI, SQL injection. |
blade_scan |
path |
Scans resources/views/ Blade templates for unescaped output ({!! !!}) and XSS-prone patterns. |
route_audit |
path |
Audits route files and middleware for missing auth, missing throttle, and CSRF exception wildcards. |
attack_simulate |
path + baseUrl |
Fires 6 live HTTP probes against a running app: SQL injection, XSS, CSRF, auth bypass, rate limiting, error disclosure. |
full_audit |
path |
Runs dependency_audit + config_audit + code_scan + blade_scan + route_audit in parallel and returns a consolidated report. |
| Pattern | Severity | Finding Type |
|---|---|---|
->whereRaw( |
High | SQL_INJECTION |
DB::raw( |
Medium | RAW_SQL_USAGE |
unserialize( |
Critical | UNSAFE_UNSERIALIZE |
shell_exec( / exec( / system( / passthru( |
Critical | RCE_RISK |
eval( |
Critical | EVAL_USAGE |
password = 'literal' |
Critical | HARDCODED_PASSWORD |
api_key = 'literal' |
Critical | HARDCODED_API_KEY |
| Long hardcoded tokens/secrets | High | HARDCODED_SECRET |
md5( |
High | WEAK_HASH_MD5 |
sha1( |
Medium | WEAK_HASH_SHA1 |
protected $guarded = [] |
High | MASS_ASSIGNMENT_UNGUARDED |
file_get_contents($request…) |
Critical | PATH_TRAVERSAL_RISK |
include/require($request…) |
Critical | LFI_RISK |
Every tool returns a structured JSON report:
{
"summary": {
"critical": 0,
"high": 1,
"medium": 2,
"low": 0,
"info": 1
},
"findings": [
{
"severity": "high",
"type": "SQL_INJECTION",
"title": "Potential SQL injection via whereRaw",
"file": "app/Http/Controllers/UserController.php",
"line": 42,
"evidence": "->whereRaw('email = ' . $email)",
"recommendation": "Avoid raw SQL with user input. Use parameter binding/query builder."
}
],
"metadata": {
"scannedPath": "/absolute/path/to/laravel-project",
"engine": "Laraguard MCP",
"version": "3.0.0",
"timestamp": "2025-01-01T00:00:00.000Z",
"durationMs": 312
}
}src/
├── index.ts — MCP server bootstrap and tool registration
├── config.ts — Environment variable loading and validation
├── security.ts — Path allowlist enforcement and secret redaction
├── files.ts — Safe file enumeration and reading
├── tools.ts — Audit tool implementations
├── reports.ts — Report aggregation and severity summarization
└── types.ts — Domain types (Finding, AuditReport, Severity, etc.)
Runtime stack:
| Component | Technology |
|---|---|
| Runtime | Node.js 20+ |
| Language | TypeScript 5.x |
| Protocol | Model Context Protocol (MCP) |
| Transport | stdio |
| Schema validation | Zod |
| MCP SDK | @modelcontextprotocol/sdk |
- Node.js 20 or higher
- npm 10 or higher
Verify your environment:
node -v
npm -vClone the repository and install dependencies:
git clone https://github.com/ecr17dev/Laraguard-MCP.git
cd "Laraguard MCP"
npm installCopy the example environment file and customise it:
cp .env.example .env| Variable | Default | Description |
|---|---|---|
MCP_BASE_PATH |
— | Single allowed root path for project scanning. |
MCP_BASE_PATHS |
— | Comma-separated list of allowed root paths. Takes precedence over MCP_BASE_PATH. |
MCP_MAX_FILES |
5000 |
Maximum number of files to enumerate per scan. |
MCP_MAX_FILE_SIZE_BYTES |
300000 |
Maximum file size (in bytes) to read per file. |
MCP_TIMEOUT_SECONDS |
30 |
Logical timeout for audit operations. |
Priority order:
MCP_BASE_PATHS→MCP_BASE_PATH→ current working directory.
# Allow scanning two project roots
MCP_BASE_PATHS="/Users/yourname/projects/my-laravel-app,/srv/workspaces/api"
# Scan limits
MCP_MAX_FILES=5000
MCP_MAX_FILE_SIZE_BYTES=300000
MCP_TIMEOUT_SECONDS=30| Command | Description |
|---|---|
npm run dev |
Runs the MCP server directly from TypeScript source using tsx (recommended for development) |
npm run build |
Compiles TypeScript to dist/ |
npm run start |
Runs the compiled server from dist/index.js |
npm run check |
Type-checks the project without emitting output |
npm run devnpm run check # Validate types first
npm run build # Emit to dist/
npm run start # Run compiled outputAdd the following to your MCP client's configuration file, replacing the path with the absolute path to your installation:
{
"mcpServers": {
"laraguard": {
"command": "node",
"args": ["/absolute/path/to/Laraguard MCP/dist/index.js"],
"env": {
"MCP_BASE_PATHS": "/absolute/path/to/your-laravel-project"
}
}
}
}If you prefer to run without building first:
{
"mcpServers": {
"laraguard": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/Laraguard MCP/src/index.ts"],
"env": {
"MCP_BASE_PATHS": "/absolute/path/to/your-laravel-project"
}
}
}
}Open Settings → MCP and paste the JSON block above. Cursor will detect the server on the next reload.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) and add the laraguard entry under mcpServers.
{ "path": "/absolute/path/to/laravel-project" }Returns basic project metadata without performing any security checks. Use it to confirm the target is a valid Laravel project and inspect framework and PHP version constraints before auditing.
{ "path": "/absolute/path/to/laravel-project" }Parses composer.lock, extracts all locked package names and versions, and queries the OSV.dev batch API for known CVEs. Each vulnerability is returned as a finding with:
- CVE/GHSA identifier and summary
- Severity (mapped from CVSS score)
- Affected package version and recommended fix version
- Direct link to the advisory page
{ "path": "/absolute/path/to/laravel-project" }| Check | File | Severity |
|---|---|---|
APP_DEBUG=true |
.env |
High |
APP_ENV=local |
.env |
Medium |
APP_KEY= (empty) |
.env |
Critical |
SESSION_SECURE_COOKIE=false |
.env |
Medium |
Wildcard CORS origin ('*') |
config/cors.php |
Medium |
{ "path": "/absolute/path/to/laravel-project" }Performs line-by-line static analysis across all PHP files. Returns every matching finding with file path, line number, and evidence snippet. See the Code Scan — Detected Patterns table above for the full rule set.
{ "path": "/absolute/path/to/laravel-project" }Scans all .blade.php files under resources/views/ for XSS-prone output patterns:
| Check | Severity |
|---|---|
{!! $variable !!} — unescaped variable |
High |
{!! request( !!} / {!! old( !!} — raw user input |
Critical |
echo $_GET / echo $_POST in blade PHP blocks |
High |
{ "path": "/absolute/path/to/laravel-project" }Reads routes/web.php, routes/api.php, and app/Http/Middleware/VerifyCsrfToken.php:
| Check | File | Severity |
|---|---|---|
Admin/dashboard route without auth middleware |
routes/web.php |
Critical |
API route without auth:sanctum / auth:api |
routes/api.php |
High |
Login/register route without throttle middleware |
Route files | Medium |
Wildcard pattern in VerifyCsrfToken::$except |
VerifyCsrfToken.php |
High |
{
"path": "/absolute/path/to/laravel-project",
"baseUrl": "http://localhost:8000"
}
⚠️ Only use against local or staging environments. Never run against production.
Fires 6 live HTTP probes against the running application:
| Probe | Method & Endpoint | What it Tests |
|---|---|---|
error_disclosure |
GET /__invalid_route__ |
Framework/stack-trace info leakage |
sql_injection_login |
POST /login with SQLi payload |
SQL injection in login form |
reflected_xss |
GET /search?q=<script>… |
Reflected XSS in search/query params |
csrf_not_enforced |
POST /login without CSRF token |
CSRF token enforcement (expects HTTP 419) |
auth_bypass |
GET /api/user without auth header |
Unauthenticated access to protected API |
rate_limit |
10× rapid POST /login |
Brute-force rate limiting (expects HTTP 429) |
The report includes a probes metadata array with the status code, duration, and triggered state for every probe.
{ "path": "/absolute/path/to/laravel-project" }Runs dependency_audit, config_audit, code_scan, blade_scan, and route_audit in parallel and merges all findings into a single consolidated report. The metadata includes per-section summaries.
Laraguard MCP implements the following controls to ensure it operates safely even when handling untrusted project paths:
- Strict path allowlisting — all file access is validated against
MCP_BASE_PATHS/MCP_BASE_PATH; path traversal attempts are rejected immediately. - File count limit — configurable cap (
MCP_MAX_FILES) prevents runaway enumeration on large monorepos. - File size limit — configurable cap (
MCP_MAX_FILE_SIZE_BYTES) prevents memory exhaustion from binary or generated files. - Directory and extension exclusions —
vendor/,node_modules/,.git/, and binary file types are excluded from scans. - Secret redaction — sensitive values (passwords, tokens, keys) are masked in textual output before being returned to the MCP client.
- Attack simulation guard —
attack_simulatealways targets only the explicitly providedbaseUrl; no automated discovery or production detection is performed.
- Laraguard MCP analyses a Laravel project as an external auditor — the Laravel application itself does not need to be running for static tools.
attack_simulaterequires the application to be running and should never target production.- The server is framework-agnostic at the transport level: any client that supports MCP stdio can use it.
- All findings are informational. Always combine automated scanning with manual code review and dedicated DAST/SAST tooling (OWASP ZAP, Burp Suite) for production security assessments.
This project is licensed under the MIT License. See LICENSE for details.