Back to skill

Security audit

Affinity Readonly

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent read-only Affinity CRM helper, but it can send the Affinity API key to any URL placed in AFFINITY_API_BASE.

Review before installing. Use only with a read-only, least-privileged Affinity token, avoid setting AFFINITY_API_BASE except in controlled testing, and prefer a version that fixes the API host to https://api.affinity.co or validates an explicit trusted allowlist. Rotate the token if this has already run where AFFINITY_API_BASE may have been manipulated.

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
scripts/affinity_get.sh:20
Finding
Affinity API Key Disclosure Through Unrestricted API Base Override<![CDATA[ ## Vulnerability Details **File Location**: `scripts/affinity_get.sh:20-37` **Related Documentation**: `SKILL.md:34` **Vulnerability Type**: Unrestricted credential transmission destination **Risk Level**: High ### Vulnerable Code ```bash base="${AFFINITY_API_BASE:-https://api.affinity.co}" if [[ "$endpoint" != /* ]]; then echo "Endpoint must start with / (example: /companies)" >&2 exit 2 fi # Prevent accidental non-GET by only supporting this script + curl GET invocation. url="${base}${endpoint}" if [[ -n "$query" ]]; then url+="?${query}" fi # Use Bearer token auth for Affinity API. # Do not echo command with key. resp="$(curl -fsS --get \ -H "Accept: application/json" \ -H "Authorization: Bearer ${AFFINITY_API_KEY}" \ "$url")" ``` The override is explicitly documented in `SKILL.md:34`: ```markdown - Base URL defaults to `https://api.affinity.co` and can be overridden with `AFFINITY_API_BASE` ``` ### Technical Analysis The script obtains the request destination from the environment variable `AFFINITY_API_BASE` without validating its scheme, hostname, or port. It then attaches `AFFINITY_API_KEY` as a Bearer token to a request sent to that destination. Although transmitting the token to the official Affinity API is necessary for the declared functionality, allowing an unrestricted destination is not. A malicious or compromised environment can redirect the request to an attacker-controlled server. The comments and documentation promise that the key will not be printed or logged, but they do not prevent it from being disclosed over the network. The endpoint check only verifies that the endpoint begins with `/`; it does not ensure that the completed URL belongs to `api.affinity.co`. Consequently, the credential’s trust boundary is controlled by mutable process configuration rather than a fixed or allowlisted service identity. ### Attack Path 1. An attacker gains the ability to influence the Skill’s environment, launch configura ...[truncated 1391 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `AFFINITY_API_BASE` support and use a fixed destination whenever production access is intended: ```bash readonly base="https://api.affinity.co" ``` 2. If an override is required for testing, parse and validate it before attaching credentials: - Require HTTPS. - Allowlist exact trusted hostnames. - Reject user-information components, fragments, unexpected ports, and nonstandard URL forms. - Reject values beginning with `-`. - Use separate, non-production credentials for test environments. 3. Disable redirects so the authorization header cannot be forwarded or accidentally exposed through destination changes. Continue avoiding `curl -L` unless every redirect target is independently validated. 4. Consider validating the complete URL with a dedicated URL parser rather than shell pattern matching. 5. Restrict the Affinity token itself to the smallest available read-only scope and rotate the existing token if the Skill has run in an environment where `AFFINITY_API_BASE` could have been manipulated. 6. Update `SKILL.md` to remove the unrestricted override guidance and explicitly document the allowed API hostname and credential trust boundary. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill invokes shell commands and external scripts but does not declare an explicit tool scope such as allowed-tools or permissions. That creates a policy gap where an agent may be permitted broader shell usage than intended, increasing the chance of unauthorized command execution, environment inspection, or misuse of local capabilities beyond the stated read-only Affinity workflow.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This shell script performs an authenticated HTTP request using the AFFINITY_API_KEY, which is a sensitive credential, but the only disclosure is in comments intended for readers of the code. There is no runtime notice, confirmation, or other user-facing warning that the script will transmit the bearer token to the configured API endpoint.

Static analysis

No suspicious patterns detected.