Back to skill

Security audit

Mailchimp

Security checks for vulnerabilities and agentic risk

Overview

This Mailchimp skill is mostly coherent and read-only, but it handles OAuth credentials while allowing an unvalidated API base and unpinned runtime tooling.

Install only if you trust the environment that provisions the Mailchimp token and API base. Prefer a version that pins mcporter and Python dependencies, validates the API base to Mailchimp HTTPS hosts, and runs with only the two required environment variables and limited outbound network access.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/server.py:21
Finding
Configurable API Base and Automatic Redirects Can Exfiltrate the Mailchimp Bearer Token<![CDATA[ ## Vulnerability Details **File Location**: `scripts/server.py`, lines 21-22, 37-40, and 61-85 **Vulnerability Type**: Bearer credential disclosure through an unvalidated network destination **Risk Level**: High ### Vulnerable Code ```python _API_BASE = os.environ.get("MAVERICK_MAILCHIMP_MCP_API_BASE", "").rstrip("/") _ACCESS_TOKEN_ENV = "MAVERICK_MAILCHIMP_MCP_ACCESS_TOKEN" ``` ```python def _api_base() -> str: if not _API_BASE: raise RuntimeError("MAVERICK_MAILCHIMP_MCP_API_BASE is required") return _API_BASE ``` ```python def _url(path: str, params: dict[str, object] | None = None) -> str: normalized_path = path if path.startswith("/") else f"/{path}" query = urllib.parse.urlencode(_clean_params(params)) url = f"{_api_base()}{normalized_path}" return f"{url}?{query}" if query else url ``` ```python def _request( access_token: str, method: str, path: str, *, params: dict[str, object] | None = None, ) -> dict[str, Any]: request = urllib.request.Request( _url(path, params), headers={ "Authorization": f"Bearer {access_token}", "Accept": "application/json", }, method=method.upper(), ) context = ssl.create_default_context(cafile=certifi.where()) try: with urllib.request.urlopen(request, timeout=30, context=context) as response: ``` ### Technical Analysis The server obtains its destination from `MAVERICK_MAILCHIMP_MCP_API_BASE` and places the OAuth bearer token in every request's `Authorization` header. `_api_base()` checks only whether the value is nonempty. It does not enforce HTTPS, validate the hostname against Mailchimp-controlled domains, reject embedded user information, restrict ports, or prevent redirects to another origin. A configurable API base is operationally useful because Mailchimp API endpoints can be data-center-specific. However, allowing an arbitrary URL exceeds the minimum network privilege require ...[truncated 2662 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the configured base with `urllib.parse.urlsplit()` before accepting it. 2. Require the `https` scheme and the default HTTPS port. 3. Allow only documented Mailchimp API hostnames. Use exact or boundary-aware validation, such as a documented data-center hostname pattern ending in `.api.mailchimp.com`; do not use a loose substring or unbounded `endswith("mailchimp.com")` check. 4. Reject URLs containing user information, fragments, unexpected paths, or encoded hostname ambiguities. 5. Disable automatic redirects for authenticated requests, or implement a redirect handler that: - allows redirects only to an explicitly approved Mailchimp origin; - rejects HTTPS-to-HTTP downgrades; - strips `Authorization` whenever the origin changes. 6. Prefer deriving the API hostname from trusted Mailchimp OAuth metadata or a validated data-center identifier rather than accepting a general-purpose URL. 7. Add tests covering malicious domains such as `api.mailchimp.com.attacker.example`, plaintext HTTP, nonstandard ports, credentials embedded in URLs, and cross-origin redirects. 8. Ensure logs and returned error objects never contain request headers or bearer-token values. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/server.py:2
Finding
Runtime Python Dependencies Are Not Reproducibly Pinned<![CDATA[ ## Vulnerability Details **File Location**: `scripts/server.py`, lines 2-7 **Vulnerability Type**: Unpinned third-party runtime dependency resolution **Risk Level**: Medium ### Vulnerable Code ```python # /// script # requires-python = ">=3.11" # dependencies = [ # "mcp>=1.27.0", # "certifi>=2025.11.12", # ] # /// ``` The execution configuration invokes this dependency-bearing script through `uv`: ```json { "command": "uv", "args": ["run", "--script", "scripts/server.py"] } ``` ### Technical Analysis Both Python dependencies use open-ended lower bounds rather than exact versions or an integrity-checked lock file. When `uv run --script scripts/server.py` resolves the environment, it may select newer releases that were not reviewed as part of this audit. The executable behavior of the Skill can therefore change without any modification to the audited project. This is particularly significant for `mcp`, which implements the local MCP server and tool exposure layer. A compromised, malicious, or unexpectedly incompatible future release would execute in the Skill process and inherit both sensitive environment variables: - `MAVERICK_MAILCHIMP_MCP_ACCESS_TOKEN` - `MAVERICK_MAILCHIMP_MCP_API_BASE` Although `certifi` has a narrower purpose, its version is also resolved dynamically. Package installation necessarily requires retrieval from a package source, but reproducibility and integrity controls should ensure that only reviewed artifacts are executed. No evidence in the audited files shows a typosquatted package or an already malicious dependency. The confirmed issue is the absence of version and artifact pinning, which creates avoidable supply-chain exposure. ### Attack Path 1. A future dependency version is compromised at its upstream package source, maintainer account, release pipeline, or distribution infrastructure. 2. The Skill is invoked in an environment where the dependency is not already resolved and cached. 3. `uv` resolves an al ...[truncated 1068 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin each Python dependency to an exact reviewed version instead of using an open-ended lower bound. 2. Generate and commit a lock file containing cryptographic hashes for all direct and transitive dependencies where the execution model supports it. 3. Configure `uv` to perform frozen or locked resolution in production and fail rather than silently updating dependencies. 4. Use a trusted, controlled package index and require TLS validation. 5. Integrate dependency vulnerability and provenance checks into release review. 6. Update dependencies through explicit, reviewed changes with automated tests, rather than resolving arbitrary future versions at invocation time. 7. Run the MCP server in a sandbox with restricted filesystem access, restricted outbound networking, and only the two required environment variables. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:13
Finding
Unpinned Global mcporter Installation Allows Unreviewed Tooling Changes<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 13-19 and 59-65 **Vulnerability Type**: Unpinned global executable dependency **Risk Level**: Medium ### Vulnerable Configuration and Documentation ```yaml install: - id: node kind: node package: mcporter bins: - mcporter label: Install mcporter (node) ``` ```markdown - **`mcporter`** ([github.com/steipete/mcporter](https://github.com/steipete/mcporter)) - MCP CLI used to invoke the local MCP server. Auto-installed via `npm install -g --ignore-scripts mcporter` if missing on PATH (see `install` spec in frontmatter). The install spec uses unpinned `mcporter` (npm `latest`); operators with strict supply-chain controls should override the install to pin a specific version. ``` ### Technical Analysis The installation specification names `mcporter` without a version, causing installation of the current npm `latest` release. The documentation explicitly acknowledges this behavior. Disabling npm lifecycle scripts with `--ignore-scripts` reduces one installation-time attack surface, but it does not make the package's runtime JavaScript trustworthy. `mcporter` is the executable that loads the configuration, receives tool arguments, spawns the Python MCP server, and passes sensitive environment variables into it. A future or compromised release can therefore alter invocation behavior before the audited server code runs. This dependency is necessary for the declared architecture, but resolving an arbitrary latest release is not necessary. An exact, reviewed version can provide the same functionality with a substantially smaller supply-chain attack surface. ### Attack Path 1. The npm package, maintainer account, or publication pipeline for `mcporter` is compromised, or an unsafe future release is tagged as `latest`. 2. A host without `mcporter` invokes the Skill's automatic installation path. 3. The unversioned install specification retrieves the malicious latest package ...[truncated 952 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `mcporter` to an exact reviewed version in the installation specification. 2. Use a lock file or npm integrity metadata and verify the expected artifact hash. 3. Prefer a project-local installation over an unscoped global installation where supported. 4. Retain `--ignore-scripts`, but do not treat it as a substitute for package pinning and runtime review. 5. Update the pinned version only through explicit security review and testing. 6. Execute `mcporter` with minimal environment variables, filesystem permissions, and outbound network access. 7. Document the exact approved version and package provenance rather than placing the burden of pinning solely on operators. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (5)

Credential Access

High
Category
Privilege Escalation
Content
- `MAVERICK_MAILCHIMP_MCP_ACCESS_TOKEN`
- `MAVERICK_MAILCHIMP_MCP_API_BASE`

Mailchimp Marketing access tokens do not use refresh tokens in this skill. If calls return auth errors, reconnect the Mailchimp integration so Maverick can provision a fresh access token and API base.

## Data flow
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `MAVERICK_MAILCHIMP_MCP_ACCESS_TOKEN`
- `MAVERICK_MAILCHIMP_MCP_API_BASE`

Mailchimp Marketing access tokens do not use refresh tokens in this skill. If calls return auth errors, reconnect the Mailchimp integration so Maverick can provision a fresh access token and API base.

## Data flow
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares environment and network-dependent behavior but does not specify any explicit tool scope such as allowed-tools or permissions. That omission weakens least-privilege enforcement and makes it harder for a host or reviewer to constrain what the skill may access, which is more concerning here because the skill handles OAuth-derived Mailchimp credentials and forwards API requests over the network.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The agent metadata broadens the advertised behavior from the skill description's read-oriented Mailchimp data access to operational capabilities such as managing campaigns and automations. This can mislead orchestrators or users into invoking state-changing functionality beyond the intended scope, increasing the risk of unauthorized marketing actions if corresponding tools exist in the runtime.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code file performs outbound HTTPS requests to a Mailchimp API using a bearer token and may transmit user query data, audience identifiers, and member-related information. While the module docstring states the general purpose, there is no confirmation prompt, logging/print disclosure, or explicit warning in the code around these data-transmitting operations.

Static analysis

No suspicious patterns detected.