# AI Agent / MCP Security Assessment — SYNTHETIC DEMO — NOT A CUSTOMER

**Issued:** 2026-11-03T22:32:13Z  
**Review ID:** `mcp-20261103-0efbaae7`  
**Prepared by:** FIRME AI CORPORATION  
**Signing key fingerprint:** `SHA256:2232b4add9b35d4016e5be270df4ed56e0dc9b39a0530ac69891073253aae90d`

> **This is not a security PASS.** It is a static review of the tool definitions supplied. It reports what was found and what was not tested. A clean section means no rule matched, not that the tool is safe.

---

## 1. Executive summary

We reviewed **8 tool definitions** and found **8 findings**: **0 critical, 3 high, 5 medium, 0 low**. The highest risk level is **HIGH** (score 70/100).

The three findings to fix first:

1. **high · destructive_action** — `tool[delete_database].description`
1. **high · ssrf_capability** — `tool[fetch_url].description`
1. **high · prompt_injection** — `tool[send_email].description`

A high or critical finding means the tool surface can be abused by a manipulated model or a buggy caller. Treat the remediation plan in section 5 as the minimum before exposing this server to an agent with real credentials.

---

## 2. Scope and systems examined

The review covers the 8 tools below, exactly as a model would receive them in a `tools/list` response. No live request was sent to a running server, no credential was used, and no source code was audited.

- `read_customer_file`
- `run_shell_command`
- `execute_sql`
- `delete_database`
- `fetch_url`
- `send_email`
- `search_docs`
- `get_weather`

---

## 3. Methodology

Deterministic structural analysis of name, description and JSON `inputSchema`:

- prompt-injection phrases aimed at the calling model;
- tool-poisoning signals (hidden instruction blocks, concealment, covert parameter channels, standing orders, remote-code instructions, secret harvesting);
- destructive verbs aimed at consequential resources;
- unbounded path, URL/SSRF and raw command/SQL/code parameters;
- credential material in descriptions or schema examples.

Every rule is a regex or structural check. Findings are candidates for a human to confirm; the report does not claim exploitation.

**Human review:** no reviewer notes were added to this report. Everything above is the engine's output only; findings are candidates, not confirmed by a person.

---

## 4. Findings

### `read_customer_file` — risk 30/100 (medium)

**1. [medium] path_scope_unbounded**  
Location: `tool[read_customer_file].description`  
Evidence: a path parameter is not scoped to a declared root; a caller can target anything the process can read: 'any file'  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Take a relative path under a declared root, canonicalise it, and reject anything that escapes the root. Run the server as a low-privilege user.

**2. [medium] path_scope_unbounded**  
Location: `tool[read_customer_file].input_schema.properties.path.description`  
Evidence: a path parameter is not scoped to a declared root; a caller can target anything the process can read: 'absolute path'  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Take a relative path under a declared root, canonicalise it, and reject anything that escapes the root. Run the server as a low-privilege user.

### `run_shell_command` — risk 30/100 (medium)

**1. [medium] unconstrained_dangerous_param**  
Location: `tool[run_shell_command].input_schema.properties.command`  
Evidence: parameter name 'command' suggests raw command/code/query execution with no enum/pattern/const constraint in its schema -- a malicious or buggy caller (or a manipulated LLM) can pass arbitrary content  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Replace the free-form parameter with an enum, a strict pattern, or a typed command allowlist; reject everything else before execution.

### `execute_sql` — risk 30/100 (medium)

**1. [medium] unrestricted_capability**  
Location: `tool[execute_sql].description`  
Evidence: the tool says it can reach anything: give it a scope (allowed directories, hosts, commands): 'Execute arbitrary SQL'  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Replace the open-ended description with the exact scope the tool is allowed to touch, and enforce that scope in code.

**2. [medium] unconstrained_dangerous_param**  
Location: `tool[execute_sql].input_schema.properties.sql`  
Evidence: parameter name 'sql' suggests raw command/code/query execution with no enum/pattern/const constraint in its schema -- a malicious or buggy caller (or a manipulated LLM) can pass arbitrary content  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Replace the free-form parameter with an enum, a strict pattern, or a typed command allowlist; reject everything else before execution.

### `delete_database` — risk 70/100 (high)

**1. [high] destructive_action**  
Location: `tool[delete_database].description`  
Evidence: a destructive verb targets a consequential resource; require an explicit approval and a scoped target: 'Delete a database'  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Require an explicit human approval bound to the exact target, or remove the tool. Scope the target to a named resource; never expose a wildcard.

### `fetch_url` — risk 70/100 (high)

**1. [high] ssrf_capability**  
Location: `tool[fetch_url].description`  
Evidence: a URL/fetch tool advertises reach into internal networks or cloud metadata: 'any URL'  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Allowlist destination hosts, block link-local and cloud-metadata addresses, resolve and pin the IP, and enforce egress at the network layer.

### `send_email` — risk 70/100 (high)

**1. [high] prompt_injection**  
Location: `tool[send_email].description`  
Evidence: matched pattern indicative of an instruction aimed at the calling LLM: 'Ignore previous instructions'  
Reproduction: request `tools/list` from the server and inspect the location above; the quoted text is the evidence. A manipulated model can act on it without any further input from the user.  
Remediation: Remove the instruction from the description. Treat tool metadata as data, not policy: sign and pin the definition, and review any change before the model sees it.

### `search_docs` — risk 0/100 (low)

- No findings matched for this tool.

### `get_weather` — risk 0/100 (low)

- No findings matched for this tool.

---

## 5. Prioritized remediation plan

1. **Contain the high and critical findings first** (section 4). If the tool cannot be scoped, remove it from the server the agent can reach.
2. **Replace free-form parameters** (`command`, `sql`, `path`, `url`) with an enum, a strict pattern or a typed allowlist, and validate in code, not in the prompt.
3. **Require approval for destructive actions**, bound to the exact target, with a signed record of who approved it.
4. **Pin the tool definitions** and review any change: a description edit is a policy change.
5. **Re-run this review** after the changes; a retest of the same surface is available as a separate engagement.

---

## 6. Limitations

- Static analysis of supplied definitions; the server was not executed.
- Heuristic rules; a finding is a candidate, and a clean result is not proof of safety.
- Does not test authentication, network exposure, runtime isolation, logging, or the model's actual behaviour.
- Does not test the tool's implementation, only its declared interface.
- No source-code review, no penetration test, no compliance certification.
- The review covers the input supplied; a tool added after the review is out of scope.

---

## 7. Retest

No retest was performed for this review. A retest repeats the same checks on the corrected surface and issues a new signed record; it is not included in the initial fixed price.

---

## 8. Default-deny policy (recommendation)

`policy.json` is a starting policy for MCPGate, generated from the findings in section 4: critical/high findings are denied, medium findings and non-read-only tools require approval, and only clearly read-only tools with no finding are allowed. An unmapped tool is denied. This is a recommendation, not a certification: review every verdict, set the tenant and downstream URL, and test it in staging before production.

---

## 9. Evidence and verification

`evidence.zip` contains the signed record, this review, the findings, the policy, the issuer's public key, and a standalone verifier that imports no CAIN code. Pin the key from a source you trust:

```
python3 verify_keystone.py --pinned-pub <PUBLIC_KEY_B64>
```

Fingerprint to compare: `SHA256:2232b4add9b35d4016e5be270df4ed56e0dc9b39a0530ac69891073253aae90d`

`INTACT` means the record is signed and unaltered. It does not mean the system is secure, and it is not a third-party audit.
