T09 · Insecure Skill Coding Practices
- Location
scripts/call.py:91- Finding
Persistent Agent Identity Seed Stored Without Restrictive Permissions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill does what it claims by contacting Fetch.ai Agentverse agents, but it also uses an API key, sends user prompts externally, and stores/reuses identity and response state in ways users should review before installing.
Install only if you are comfortable sending selected prompts to Fetch.ai Agentverse agents and using an AGENTVERSE_API_KEY for mailbox registration. Avoid submitting sensitive, private, or proprietary content; run it in a limited environment; and treat the persistent seed and /tmp response file as local state that may need cleanup or tighter permissions on shared machines.
scripts/call.py:91Persistent Agent Identity Seed Stored Without Restrictive Permissions
scripts/fire.sh:5Predictable Shared Temporary File Allows Response Disclosure, Tampering, and Symlink Clobbering
SKILL.md:12Unpinned Third-Party Agent Dependencies Create Supply-Chain Exposure
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
},
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
agents = data.get("agents", [])
if agents:
The code reads AGENTVERSE_API_KEY from the environment and posts it to a local HTTP /connect endpoint for mailbox registration. While this appears intended functionality, it creates a credential flow not disclosed in the skill description and relies on an unauthenticated localhost service, so a compromised or unexpected local listener on that port could receive the token.
headers={"Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
body = resp.read().decode()
if resp.status == 200:
ctx.logger.info("Mailbox registered with Agentverse")
The skill invokes code execution, accesses an API key from the environment, performs network calls to third-party agents, and appears to write/read intermediate results, but it declares no explicit tool scope or permission boundaries. That creates an authorization and review gap: the host agent may grant broader capabilities than users or operators expect, increasing the chance of unintended data exposure or unsafe execution.
The description is broad enough to trigger on generic requests about AI agents, messaging, discovery, or Fetch.ai-related topics, which can cause the skill to activate in situations where the user did not intend an external agent call. Over-broad activation increases the risk of accidental data transmission and unexpected tool execution, especially because this skill can contact remote agents and use an API-backed service.
The skill directs the agent to send user queries to third-party Agentverse agents and marketplace services without requiring a user-facing disclosure or consent step. This is dangerous because users may unknowingly transmit sensitive prompts, identifiers, or proprietary data to external systems with different retention, logging, or security practices.
The script silently persists a generated agent identity seed to a local .seed file, creating stateful identity material not mentioned in the manifest. Even though this is likely for convenience, undocumented persistence can surprise users and may expose identity material if file permissions or workspace handling are weak.
The skill has undeclared credential-handling behavior: it reads AGENTVERSE_API_KEY and performs mailbox auto-registration, which is broader than the stated purpose of merely searching and messaging agents. Hidden or insufficiently disclosed credential use increases trust and privacy risk because users may not realize the skill will consume and transmit an API token.
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
"user_token": api_key,
"agent_type": "mailbox",
}).encode()
req = urllib.request.Request(
f"http://localhost:{port}/connect",
data=payload,
headers={"Content-Type": "application/json"},
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OUTFILE="/tmp/fetch-agents-$(whoami)-response.txt"
echo "PENDING" > "$OUTFILE"
nohup python3 "$SCRIPT_DIR/call.py" "$@" > "$OUTFILE" 2>/dev/null &
disown
echo "Agent call started. Poll with result.sh in ~40 seconds."
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
OUTFILE="/tmp/fetch-agents-$(whoami)-response.txt"
echo "PENDING" > "$OUTFILE"
nohup python3 "$SCRIPT_DIR/call.py" "$@" > "$OUTFILE" 2>/dev/null &
disown
echo "Agent call started. Poll with result.sh in ~40 seconds."
No suspicious patterns detected.