abudzar.io Book a scoping call
This is a sample. Meridian Freight Systems is a fictional company; every server, credential, and finding below is fabricated. The structure, depth, and grading are exactly what a real engagement delivers. Real reports are confidential and redacted by the client before anything is shared.
SAMPLE · REDACTED

MCP & AI-Agent Exposure Audit
Final Report

CLIENT
Meridian Freight Systems (fictional) — logistics, ~140 engineers
ENGAGEMENT
Fixed-fee exposure audit · 2 weeks · read-only access
SCOPE
14 agreed repositories, CI configuration, developer MCP client configs, existing monitoring. Out of scope: endpoint fleet scanning, penetration testing, production changes.
AUDITOR
Abu Dzar · abudzar.io
CLASSIFICATION
Confidential — client-redacted sample for publication
// 0 · executive summary

11 MCP servers found. Security knew about 4 of them.

Within the agreed scope we identified 11 MCP servers wired into Claude Code, Cursor, and an internal agent runner. 7 were absent from any asset register. 4 hold credentials that can reach production systems. 2 findings are graded Critical: a static database credential embedded in a shared client config, and a deployment tool callable by an LLM with no approval gate and no audit trail.

None of this is unusual. MCP adoption at Meridian followed the pattern we see everywhere: individual developers solved local problems, the configs spread through dotfile repos and onboarding docs, and no single team ever owned the full picture. The remediation roadmap in §5 is sequenced so that the two Critical items are closed in week one with configuration changes only.

// 1 · inventory

Complete agent & MCP server inventory

Discovered via repository and CI scanning of the agreed scope: client configs (claude_desktop_config.json, .cursor/mcp.json, .mcp.json), CI pipeline definitions, and the internal agent runner's deployment manifests.

IDServerOwnerTransportFound inKnown to security?Prod reach
S-01postgres-mcp▮▮▮▮▮▮▮ (Platform)stdioinfra-tools repo, 23 dev configsNoYes — replica + primary
S-02github-mcpDev Productivitystdioonboarding doc, dotfilesYesIndirect (CI secrets)
S-03deploy-helper (internal)▮▮▮▮▮ (SRE)stdiosre-scripts repoNoYes — kubectl apply
S-04filesystemindividual devsstdio31 dev configs, scoped to ~/NoNo
S-05jira-mcpDev ProductivitySSE (vendor-hosted)team wikiYesNo
S-06slack-mcp▮▮▮▮▮▮stdio2 dev configsNoNo (data exposure only)
S-07s3-mcpData Engstdiodata-pipelines repoYesYes — prod buckets r/w
S-08grafana-mcpSREstdiosre onboardingYesRead-only
S-09internal-api-mcp▮▮▮▮▮▮▮▮ (Checkout)stdiocheckout-svc repoNoYes — staging + prod API
S-10browser-mcpindividual devsstdio4 dev configsNoNo
S-11agent-runner tools (internal)AI EnablementHTTP (internal)agent-runner manifestsNoStaging only
// 2 · blast-radius map

What each server can actually do

Capability matrix for the four servers with production reach. "Destructive" means a tool an LLM can invoke that deletes, overwrites, or deploys without human confirmation.

IDReadsWritesDestructive toolsCredential heldRotation
S-01All schemas incl. ▮▮▮▮▮▮_customersYes (no table allow-list)execute_sql — unrestrictedStatic password, shared roleNever (412 days)
S-03Cluster state, all namespacesYesapply_manifest, delete_podCluster-admin kubeconfig90 days
S-07All prod bucketsYesdelete_objectIAM user key, ▮▮▮▮▮▮▮▮▮▮Never (688 days)
S-09Orders, customers, pricingYes (POST/PUT pass-through)refund_order (no cap)Service token, admin scope180 days

The remaining seven servers are capability-bounded (read-only, non-production, or local filesystem scope) and are covered in Appendix B of the full report.

// 3 · findings

Graded findings

Graded against the OWASP Top 10 for LLM Applications (2025) plus MCP-specific checks. 9 findings total in the full report; 6 shown in this sample.

F-01Static production database credential in a config shared across 23 developer machinesCRITICAL

Evidence. The postgres-mcp entry distributed via the infra-tools repo embeds a plaintext connection string for a shared role with write access to the primary. The credential has not rotated in 412 days and appears in 23 checked-out configs:

"postgres": {
  "command": "npx", "args": ["-y", "postgres-mcp"],
  "env": { "DATABASE_URL": "postgres://app_shared:▮▮▮▮▮▮▮▮▮▮▮▮@db-prod-▮▮▮.meridian.internal:5432/meridian" }
}

Impact. Any prompt-injected or misbehaving agent session on any of 23 laptops can read or modify production data. Any laptop compromise yields the credential directly.

Remediation. Rotate immediately; replace with per-developer short-lived credentials (IAM auth or Vault dynamic secrets); point the MCP server at a read replica with a least-privilege role.

OWASP LLM06 (Sensitive Information Disclosure) · LLM08 (Excessive Agency) · scope: S-01
F-02Deployment tool callable by an LLM with no approval gate and no audit trailCRITICAL

Evidence. The internal deploy-helper server exposes apply_manifest with a cluster-admin kubeconfig. Tool calls are not logged anywhere; the only record is the agent conversation on the developer's machine. A deployment triggered this way is indistinguishable from a manual one in cluster audit logs.

Impact. An agent can modify production workloads, and the org cannot reconstruct what an agent did after the fact — the exact incident-response gap described in the engagement brief.

Remediation. Gate destructive tools behind explicit confirmation; scope the kubeconfig to a namespaced role; log every tool call (request, arguments, outcome) to the SIEM — §4 gives the vendor-neutral pattern.

OWASP LLM08 (Excessive Agency) · LLM02 (via tool output) · scope: S-03
F-03Long-lived IAM user key with delete rights on production bucketsHIGH

Evidence. s3-mcp authenticates with an IAM user access key (688 days old) granting s3:* on production buckets, including DeleteObject, used from developer laptops.

Remediation. Replace with role assumption + short-lived session credentials; strip delete permissions; enable bucket versioning and object lock on the two buckets holding customer manifests.

OWASP LLM08 · CIS AWS 1.4 · scope: S-07
F-04Unpinned third-party MCP servers fetched at launch via npx -yHIGH

Evidence. 8 of 11 servers launch as npx -y <package> with no version pin and no integrity check — every agent session executes whatever the registry serves that day, with the credentials in that server's env block.

Remediation. Pin exact versions; mirror vetted packages in the internal registry; prefer single-binary servers where available.

OWASP LLM05 (Supply Chain) · scope: S-01,02,04,06,07,08,10 + 1 more
F-05Tool descriptions ingested from a vendor-hosted server without review (tool-poisoning surface)MEDIUM

Evidence. The vendor-hosted jira-mcp (SSE) delivers tool descriptions at runtime. Descriptions are rendered into every agent's context unreviewed; a malicious or compromised description can steer agent behavior across all connected developers simultaneously.

Remediation. Snapshot and diff tool descriptions in CI; alert on changes; treat description changes as a change-management event.

OWASP LLM01 (Prompt Injection, indirect) · scope: S-05
F-06No inventory ownership: 7 of 11 servers absent from the asset registerMEDIUM

Evidence. No team owns the MCP surface. 7 servers were unknown to security before this audit; 3 had no identifiable owner at all and were attributed via git blame on the introducing commit (▮▮▮▮▮▮▮▮▮).

Remediation. Add MCP servers as an asset class in the register; require an owner and a capability declaration per server; review quarterly. A one-page policy template is included in Appendix C.

Governance · supports SOC 2 CC6.1 evidence · scope: all
// 4 · observability gap assessment

What your monitoring can and cannot see today

Mapped against the question that matters in an incident: "could we reconstruct what an agent did in five minutes?" Today the answer at Meridian is no, for every server.

Agent actionVisible today?Where it should land
Tool call issued (name + args)No — exists only in local chat historyStructured log → SIEM
Tool call latency / error ratesNoPrometheus metrics per server
DB queries from S-01Partial — pg logs, not attributable to agent vs humanDedicated role per server → attributable
Deploys from S-03No — indistinguishable from manual kubectlAudit-logged service account per agent
Server process up/downNoLiveness metric, alert on flap

Recommended pattern (vendor-neutral). Wrap each stdio server with a transparent observability proxy emitting Prometheus metrics and a structured JSON event log (the open-source mcpobserve is one zero-dependency option; an OTel collector sidecar is another), route the event log to the existing Splunk pipeline, and add the five dashboard panels specified in Appendix D. Estimated effort: 2–3 engineer-days for all 11 servers.

// 5 · remediation roadmap

Sequenced by risk × effort

#ActionClosesRisk ↓EffortOwnerWhen
R-1Rotate S-01 credential; move to read replica + least-privilege roleF-01CriticalHoursPlatformWeek 1
R-2Scope S-03 kubeconfig to namespaced role; confirmation gate on apply/deleteF-02Critical1 daySREWeek 1
R-3Replace S-07 IAM user key with assumed role; strip delete; enable versioningF-03High1 dayData EngWeek 1–2
R-4Pin all MCP server versions; mirror in internal registryF-04High2 daysDev ProdWeek 2
R-5Deploy observability proxy + SIEM routing on the 4 prod-reach servers§4High2–3 daysSREWeek 2–3
R-6Tool-description snapshot/diff in CI for vendor-hosted serversF-05Medium1 dayDev ProdWeek 3
R-7MCP asset-class policy: owner, capability declaration, quarterly reviewF-06MediumPolicySecurityWeek 4

Full report additionally includes: Appendix A (per-server config evidence), B (capability matrix for all 11 servers), C (policy template), D (dashboard & alert specifications), and the 30-minute executive readout deck.

// your environment, this report

Want this map of your own agent surface?

Fixed fee, two weeks, read-only. Founding-client rate in exchange for a case study you redact and approve.

Book a free 20-min scoping call →