Back to skill

Security audit

Graphiti

Security checks for vulnerabilities and agentic risk

Overview

This Graphiti skill has a coherent purpose, but its documented shell command templates can execute unintended local commands if user-supplied query or memory text contains shell syntax.

Install only if you trust the configured Graphiti server and understand that search terms and added memories are sent to it, with added memories persisted there. The publisher should replace the documented curl templates with jq-generated JSON or another structured request method before broad use, and users should avoid submitting secrets or sensitive data until that is fixed.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:24
Finding
Shell Command Injection Through Unsafely Interpolated Graphiti Input<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:24-30`, `SKILL.md:38-43`, `SKILL.md:64-70`, and `SKILL.md:75-80` **Vulnerability Type**: Shell command injection caused by embedding variable content in single-quoted JSON shell arguments **Risk Level**: High ### Vulnerable Code Search operation (`SKILL.md:24-30`): ```bash bash command:" GRAPHITI_URL=\$({baseDir}/references/env-check.sh) curl -s -X POST \"\$GRAPHITI_URL/facts/search\" \ -H 'Content-Type: application/json' \ -d '{\"query\": \"YOUR_QUERY\", \"max_facts\": 10}' | jq . " ``` Episode creation operation (`SKILL.md:38-43`): ```bash bash command:" GRAPHITI_URL=\$({baseDir}/references/env-check.sh) curl -s -X POST \"\$GRAPHITI_URL/messages\" \ -H 'Content-Type: application/json' \ -d '{\"name\": \"EPISODE_NAME\", \"content\": \"EPISODE_CONTENT\"}' | jq . " ``` The same unsafe command construction is repeated in the examples at `SKILL.md:64-70` and `SKILL.md:75-80`. ### Technical Analysis The skill instructs the agent to replace `YOUR_QUERY`, `EPISODE_NAME`, and `EPISODE_CONTENT` directly inside JSON enclosed by a single-quoted shell argument. JSON escaping and shell escaping are separate security boundaries. An apostrophe in attacker-controlled content terminates the shell's single-quoted argument, after which shell metacharacters can introduce additional commands. For example, if an episode value is substituted with content structurally resembling: ```text x'; id > /tmp/graphiti-injection; # ``` the apostrophe can close the argument, the semicolon can terminate the `curl` command fragment, and the remaining text can be parsed as a new shell command. The exact payload may require adjustment for the command wrapper used by the agent, but the underlying unsafe composition permits shell syntax to escape the intended JSON value. The issue affects both read and write workflows because graph search terms and episode fields can originate from user instructions. Quoting the URL ...[truncated 1634 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not create JSON request bodies by inserting user-controlled text into shell command templates. Keep untrusted values in shell variables and use `jq` to perform JSON encoding: ```bash query="$1" payload=$(jq -n --arg query "$query" --argjson max_facts 10 \ '{query: $query, max_facts: $max_facts}') curl --fail --silent --show-error \ -X POST "$GRAPHITI_URL/facts/search" \ -H 'Content-Type: application/json' \ --data-binary "$payload" ``` For episode creation: ```bash name="$1" content="$2" payload=$(jq -n --arg name "$name" --arg content "$content" \ '{name: $name, content: $content}') curl --fail --silent --show-error \ -X POST "$GRAPHITI_URL/messages" \ -H 'Content-Type: application/json' \ --data-binary "$payload" ``` Additional hardening should include: 1. Pass user values through positional parameters or environment variables rather than substituting them into executable command text. 2. Avoid `eval`, nested shell construction, or any mechanism that reparses generated strings as commands. 3. Apply strict input-size limits to graph queries, names, and episode content. 4. Run the skill under a dedicated, least-privileged operating-system account. 5. Limit outbound network access to approved Graphiti endpoints. 6. Prefer authenticated HTTPS endpoints over plaintext HTTP for non-local deployments. 7. Add regression tests containing apostrophes, semicolons, command substitutions, newlines, backticks, and JSON control characters to verify that all input remains data rather than shell syntax. 8. Update every duplicated command example in `SKILL.md`; leaving an unsafe example may cause the agent to reproduce the vulnerable pattern. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Vague Triggers

Medium
Confidence
92% confidence
Finding
The README demonstrates activation from a very broad natural-language request ('Search for information about our project') without describing any gating, confirmation, or scope restrictions. In an agentic system, vague triggers can cause the skill to be invoked unexpectedly on unrelated prompts, leading to unnecessary data access or disclosure from the connected knowledge graph.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill exposes shell-based capabilities that can make outbound HTTP requests, but it declares no permissions or allowed-tools scope. This weakens least-privilege controls and can cause an agent or reviewer to underestimate the skill's ability to transmit or persist data.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
bash command:"
GRAPHITI_URL=\$({baseDir}/references/env-check.sh)
curl -s -X POST \"\$GRAPHITI_URL/facts/search\" \
  -H 'Content-Type: application/json' \
  -d '{\"query\": \"YOUR_QUERY\", \"max_facts\": 10}' | jq .
"
Confidence
89% confidence
Finding
This command sends user-supplied query data over HTTP to an external Graphiti service discovered dynamically from config or environment. Even though this is core functionality, it still transmits potentially sensitive prompts or graph queries to a network service and could leak data if the endpoint is misconfigured or points to an untrusted host.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The documentation includes a write operation that stores episodes in the knowledge graph without warning that submitted content will be persisted and may include sensitive user data. This creates a realistic risk of users or agents sending confidential information into long-lived storage unintentionally.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
bash command:"
GRAPHITI_URL=\$({baseDir}/references/env-check.sh)
curl -s -X POST \"\$GRAPHITI_URL/messages\" \
  -H 'Content-Type: application/json' \
  -d '{\"name\": \"EPISODE_NAME\", \"content\": \"EPISODE_CONTENT\"}' | jq .
"
Confidence
97% confidence
Finding
This command posts episode name and content to the Graphiti service, causing explicit external transmission and persistence of supplied data. Because the content can contain arbitrary memory text, the combination of dynamic endpoint discovery and silent storage increases the risk of exfiltration or long-term retention of sensitive information.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
bash command:"
GRAPHITI_URL=\$({baseDir}/references/env-check.sh)
curl -s -X POST \"\$GRAPHITI_URL/facts/search\" \
  -H 'Content-Type: application/json' \
  -d '{\"query\": \"Tell me about Essam Masoudy\", \"max_facts\": 5}'
"
Confidence
86% confidence
Finding
The example demonstrates sending a natural-language query to the Graphiti API, which is another instance of outbound data transmission. In context this is expected behavior for a knowledge-graph skill, but it still expands the attack surface because users may paste sensitive content and the target service is resolved dynamically.

Static analysis

No suspicious patterns detected.