Back to skill

Security audit

Ucm

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent API marketplace integration, but it handles a paid-service bearer key in ways that can expose it and does not clearly gate external data-sharing or spending.

Review this skill before installing. It appears intended to provide UCM marketplace access, not to hide malicious behavior, but you should only use it if you are comfortable sending task data to UCM and upstream providers and with small paid calls being made. Avoid printing or pasting full API keys into agent transcripts or logs, store ~/.config/ucm/credentials.json with restrictive permissions, and rotate the key if it has already appeared in logs.

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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:131
Finding

API Credentials Exposed Through Standard Output

Content
View full analysis
/dev/null ``` If the file exists and contains an `api_key`, set it and skip registration: ```bash export UCM_API_KEY=$(cat ~/.config/ucm/credentials.json | grep -o '"api_key":"[^"]*"' | head -1 | sed 's/"api_key":"//;s/"$//') ``` ``` From `scripts/register.sh` when an existing credential is found: ```bash if [ -n "$EXISTING_KEY" ]; then echo "Already registered! Credentials found at $CREDENTIALS_PATH" echo "" echo "API Key: $EXISTING_KEY" echo "" echo "Set it as an environment variable:" echo " export UCM_API_KEY=\"$EXISTING_KEY\"" exit 0 fi ``` From `scripts/register.sh` after registration: ```bash echo "Registration successful!" echo "" echo "API Key: $API_KEY" echo "Credentials saved to: $CREDENTIALS_PATH" echo "" echo "Set it as an environment variable:" echo " export UCM_API_KEY=\"$API_KEY\"" ``` ### Technical Analysis The setup documentation directs the agent or user to print the entire credentials file. The registration script also prints both existing and newly issued API keys to standard output, including a ready-to-copy shell export command. An API key is a bearer credential. Any party that obtains it can authenticate without an additional password or proof of identity. Standard output is not an appropriate secret-delivery channel because it may be captured by: - AI-agent conversation transcripts - CI/CD job logs - Shell session recording - Terminal scrollback - Process wrappers and orchestration systems - Support bundles or diagnostic logs Reading the Skill-specific credentials file is necessary when no environment variable is available. Printing its contents or the extracted key is no ...[truncated 1315 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/register.sh:76
Finding

Credential File Created Without Explicitly Restrictive Permissions

Content
View full analysis
/dev/null 2>&1; then echo "$BODY_RESPONSE" | jq '{api_key: .api_key, agent_id: .agent_id, registered_at: .credentials_to_save.registered_at}' > "$CREDENTIALS_PATH" else REGISTERED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ") printf '{\n "api_key": "%s",\n "agent_id": "%s",\n "registered_at": "%s"\n}\n' "$API_KEY" "$AGENT_ID" "$REGISTERED_AT" > "$CREDENTIALS_PATH" fi ``` ### Technical Analysis The script stores a plaintext bearer token in `~/.config/ucm/credentials.json` but does not set a restrictive `umask`, directory mode, or file mode. The resulting permissions depend on the caller's environment. Under a common `umask 022`, a newly created file can receive mode `0644` and the directory can receive mode `0755`. On a multi-user system, this may allow other local users to read the credential. Existing files are also overwritten without first verifying or correcting their ownership and permissions. The redirection writes directly to the final credentials path. If the process is interrupted, the credential file may be left partially written. Direct writing also provides weaker protection against filesystem races than creating a securely permissioned temporary file and atomically renaming it. ### Attack Path 1. The victim runs the registration script with a permissive umask. 2. The script creates `~/.config/ucm/credentials.json` without an explicit mode. 3. The file receives permissions that permit unintended local reads. 4. Another local user, process, or compromised service account reads the plaintext API key. 5. The attacker uses the key to authenticate to UCM and perform operations within the token's authority. Successful exploitation requires local access or access through anoth ...[truncated 478 chars]
Remediation
View remediation
"$TMP_FILE" mv -f "$TMP_FILE" "$CREDENTIALS_PATH" ``` 4. Install a trap to delete the temporary file if registration fails. 5. Verify that the final path is a regular file owned by the current user and is not an unexpected symbolic link. 6. Correct permissions on existing installations: ```bash chmod 700 "$HOME/.config/ucm" chmod 600 "$HOME/.config/ucm/credentials.json" ``` ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/register.sh:23
Finding

Python Code Injection Through Interpolated Credentials Path

Content
View full analysis
/dev/null 2>&1; then EXISTING_KEY=$(python3 -c "import sys,json; print(json.load(open('$CREDENTIALS_PATH')).get('api_key',''))" 2>/dev/null) ``` `CREDENTIALS_PATH` is initialized from the environment-controlled `HOME` variable: ```bash CREDENTIALS_PATH="$HOME/.config/ucm/credentials.json" ``` ### Technical Analysis The credentials path is interpolated directly into the source text supplied to `python3 -c`. Although the shell expansion occurs inside double quotes, the expanded value is inserted between single quotes in the generated Python program. A crafted `HOME` value containing a single quote and valid Python syntax can terminate the intended Python string and alter the program executed by `python3`. This is source-code injection rather than shell command injection. The vulnerable branch is reached only when: - The credentials path exists - `jq` is unavailable - `python3` is available - The attacker can influence the environment, particularly `HOME` These prerequisites reduce severity, but the code pattern is still exploitable in automated or adversarial invocation contexts. ### Attack Path 1. An attacker controls or influences the environment used to invoke `register.sh`, including `HOME`. 2. The attacker supplies a crafted `HOME` value that causes `$CREDENTIALS_PATH` to contain Python syntax. 3. The attacker arranges for the corresponding path check to succeed. 4. `jq` is absent, causing execution to enter the Python fallback. 5. The crafted path is inserted into the `python3 -c` source. 6. Python executes the injected statements with the privileges of the user running the script. This is primarily relevant where a privileged or trusted wrapper invokes the script while preserving attacker-controlled environment variables. ### Impact Assessment ...[truncated 534 chars]
Remediation
View remediation
/dev/null 2>&1; then EXISTING_KEY=$( python3 -c ' import json import sys with open(sys.argv[1], encoding="utf-8") as credential_file: print(json.load(credential_file).get("api_key", "")) ' "$CREDENTIALS_PATH" 2>/dev/null ) ``` Additional hardening should include: 1. Validate that `HOME` is an absolute, expected user home directory when running in a privileged automation context. 2. Avoid constructing executable language source from environment variables or filenames. 3. Verify that the credential path is a regular file owned by the current user before opening it. 4. Prefer one well-defined JSON parser rather than regex-based parsing of JSON. 5. Ensure privileged wrappers reset or explicitly set security-sensitive environment variables instead of inheriting them from untrusted callers. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description claims a broad functional skill that provides access to and invocation of many external APIs. The actual code chunk only handles agent registration against registry.ucm.ai, checks for an existing local credentials file, saves returned credentials, and displays an example of how a user might later call one service. That example output is not the same as implementing the marketplace access itself. While free registration and $1.00 credits are consistent with the description, the primary purpose of the provided code is registration/bootstrap, not discovery and calling of external capabilities. Therefore the code materially under-delivers relative to the declared purpose.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The skill explicitly directs access to a local credentials file, which is a high-risk behavior in an agent context because it involves reading secrets from the filesystem. Even if intended only for this product's key, it establishes a pattern of local secret harvesting and may expose the value through shell history, process listings, tool output, or later prompts.

Content

Scanner excerpt · SKILL.md (reported line 134)May include surrounding context.

Check for existing credentials first

bash
cat ~/.config/ucm/credentials.json 2>/dev/null

If the file exists and contains an api_key, set it and skip registration:

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The export command extracts the API key from the credentials file using shell pipelines, increasing the risk of accidental exposure through command history, debugging output, or unsafe reuse. Parsing and exporting secrets in plaintext is especially dangerous on shared or instrumented systems.

Content

Scanner excerpt · SKILL.md (reported line 139)May include surrounding context.

If the file exists and contains an api_key, set it and skip registration:

bash
export UCM_API_KEY=$(cat ~/.config/ucm/credentials.json | grep -o '"api_key":"[^"]*"' | head -1 | sed 's/"api_key":"//;s/"$//')

If you need to register

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The decision flow normalizes checking a local secret file as part of ordinary operation. In a skill ecosystem, instructions that encourage filesystem secret access broaden capability scope and increase the chance that agents access data beyond what the user intended.

Content

Scanner excerpt · SKILL.md (reported line 216)May include surrounding context.

│ ├─ Credits available → Discover → Call → Use result │ ├─ Call failed → Credits auto-refunded, try alternative │ └─ No credits → Tell user to add credits at dashboard.ucm.ai ├─ No API key? → Check ~/.config/ucm/credentials.json │ └─ Found? → Load api_key from file └─ No credentials at all? → Register (POST /v1/agents/register) → Save to ~/.config/ucm/credentials.json

text

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

The skill instructs saving credentials to a predictable path on disk, creating a persistent local secret target. Predictable secret locations are attractive to malware and other compromised tools, and the guidance lacks permission-hardening or encryption requirements.

Content

Scanner excerpt · SKILL.md (reported line 218)May include surrounding context.

│ └─ No credits → Tell user to add credits at dashboard.ucm.ai ├─ No API key? → Check ~/.config/ucm/credentials.json │ └─ Found? → Load api_key from file └─ No credentials at all? → Register (POST /v1/agents/register) → Save to ~/.config/ucm/credentials.json

text

## Spending Principles

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'shell' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/register.sh (reported line 7)May include surrounding context.

sh
#
# Registers a new agent on UCM and returns the API key.
# The agent receives $1.00 in free credits immediately.
# Credentials are saved to ~/.config/ucm/credentials.json
#
# Dependencies: curl (required), jq or python3 (optional, for pretty output)

Credential Access

High
Category
Privilege Escalation
Confidence
79% confidence
Finding

The script stores sensitive API credentials in ~/.config/ucm/credentials.json but does not set restrictive file permissions such as 0600. On multi-user systems or permissive umask settings, this can leave the credential file readable by other local users, exposing the API key for unauthorized use.

Content

Scanner excerpt · scripts/register.sh (reported line 16)May include surrounding context.

sh
REGISTRY_URL="https://registry.ucm.ai"
AGENT_NAME="${1:-my-agent}"
DESCRIPTION="${2:-}"
CREDENTIALS_PATH="$HOME/.config/ucm/credentials.json"

# Check if already registered
if [ -f "$CREDENTIALS_PATH" ]; then

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill advertises paid third-party actions, including email sending and many external API calls, without a clear user-facing warning that task data may be transmitted externally and that charges may be incurred. In agent workflows, this can lead to unintended disclosure of sensitive user content or unauthorized spending.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill instructs the agent to read a local credentials file to obtain an API key, which expands its behavior from simple API usage into local secret access. In an agent setting, encouraging arbitrary file reads can normalize access to local sensitive material and may expose credentials to logs, prompts, or downstream tools if mishandled.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill includes registration and credential persistence steps that create and store account credentials locally, going beyond simple capability discovery/calling. This broadens the trust boundary and can leave long-lived secrets on disk without clear consent, rotation guidance, or storage protections.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
85% confidence
Finding

This step transmits data to an external service to register an account and receive credentials. External transmission is expected for this skill's purpose, but it is still security-relevant because it creates an outbound data flow and third-party account relationship without an explicit warning or approval checkpoint.

Content

Scanner excerpt · SKILL.md (reported line 147)May include surrounding context.

Register for free — takes one HTTP call:

bash
curl -s -X POST https://registry.ucm.ai/v1/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent"}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The instructions tell the user/agent to save returned credentials to disk but omit a warning that these are sensitive secrets and should be stored with restricted permissions. Persisting API keys locally without guidance increases the chance of credential theft from other local processes, shared environments, or accidental inclusion in backups.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

Creating a config directory and persisting credentials introduces session persistence for an external service account. Persistence is not inherently malicious, but without user consent and secure storage controls it increases the blast radius of host compromise and enables reuse of credentials beyond the immediate task.

Content

Scanner excerpt · SKILL.md (reported line 154)May include surrounding context.

The response includes credentials_to_save and credentials_path. Save them:

bash
mkdir -p ~/.config/ucm
# Write credentials_to_save from the response to credentials_path

External Transmission

Medium
Category
Data Exfiltration
Confidence
81% confidence
Finding

The discover request sends natural-language task descriptions to a third-party service. Because those descriptions may contain sensitive user context, this can leak private or proprietary information if the agent forwards prompts verbatim without warning.

Content

Scanner excerpt · SKILL.md (reported line 203)May include surrounding context.

Search by natural language — no auth required:

bash
curl -s -X POST https://registry.ucm.ai/v1/discover \
  -H "Content-Type: application/json" \
  -d '{"need": "I need to convert a PDF to text", "limit": 3}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The catalog documents many services that transmit user-provided content to external providers, including web scraping, code execution, email, speech, document conversion, and search, but it provides no privacy, consent, data-handling, or third-party disclosure guidance. In an agent setting, this can cause sensitive prompts, documents, audio, URLs, or recipient data to be forwarded off-platform without user awareness, increasing risk of privacy violations and unintended data exposure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/register.sh (reported line 53)May include surrounding context.

sh
fi

# Register
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${REGISTRY_URL}/v1/agents/register" \
  -H "Content-Type: application/json" \
  -d "$BODY")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script prints the newly issued API key directly to stdout, and also prints an existing key when already registered. Secrets echoed to the terminal can be captured by CI logs, shell session recording, terminal scrollback, or shared consoles, which increases the chance of credential exposure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/register.sh (reported line 94)May include surrounding context.

sh
echo "  export UCM_API_KEY=\"$API_KEY\""
    echo ""
    echo "You have \$1.00 in free credits. Try a web search:"
    echo "  curl -s -X POST ${REGISTRY_URL}/v1/call \\"
    echo "    -H \"Authorization: Bearer \$UCM_API_KEY\" \\"
    echo "    -H \"Content-Type: application/json\" \\"
    echo "    -d '{\"service_id\":\"ucm/web-search\",\"endpoint\":\"search\",\"params\":{\"query\":\"hello world\"}}'"

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The ucm/news section specifies lang as optional with default en, which imposes a language default in the natural-language behavior of the skill documentation without any opt-in or explanation. Under the policy rule, forced or implicit language defaults can be a locale-policy concern when user choice is not surfaced.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.