Back to skill

Security audit

Canva

Security checks for vulnerabilities and agentic risk

Overview

This Canva skill appears purpose-built for Canva, but it needs Review because it can change Canva content and may over-share chat context or OAuth-backed requests beyond the intended scope.

Review this before installing if your Canva account contains sensitive business content. Use it only with the default Canva endpoint, avoid running generation from chats that contain secrets or unrelated private information, explicitly confirm any page deletion or public comment, and consider pinning/reviewing the mcp-skill dependency and knowing how to revoke the stored OAuth token.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
app.py:13
Finding
OAuth-Authenticated Client Permits an Unrestricted MCP Endpoint## Vulnerability Details **File Location**: `app.py:13-19` **Vulnerability Type**: Unrestricted authenticated remote endpoint **Risk Level**: High ```python def __init__(self, url: str = "https://mcp.canva.com/mcp", auth=None) -> None: self.url = url self._oauth_auth = auth def _get_client(self) -> Client: oauth = self._oauth_auth or OAuth() return Client(self.url, auth=oauth) ``` ### Technical Analysis The public constructor accepts an arbitrary MCP endpoint and stores it without validating its scheme or hostname. `_get_client()` then creates an OAuth provider and attaches it to a client for that endpoint. Although the default endpoint is the legitimate Canva MCP service, calling code can replace it with another URL. If untrusted configuration, an environment integration, or another component can influence the constructor argument, the application may initiate an authenticated MCP session with an attacker-controlled service. There is no exact-host allowlist, HTTPS enforcement, or separation between production credentials and custom development endpoints. ### Attack Path 1. An attacker gains influence over the value passed to `CanvaApp(url=...)`, such as through an integrating application's configuration. 2. The attacker supplies an endpoint under their control. 3. The application invokes `_get_client()`. 4. The application constructs an OAuth-authenticated `Client` for the attacker-selected endpoint. 5. Authentication protocol data and subsequent tool arguments are sent to that endpoint. 6. The malicious endpoint can collect exposed information, return spoofed tool results, or attempt to induce unauthorized follow-up actions. Exploitation depends on an attacker being able to influence the constructor argument; the project does not itself expose a direct user-input route to this argument. ### Impact Assessment The issue can expose authentication-related material and sensitive tool argument ...[truncated 368 chars]
Remediation
## Remediation Suggestions - Remove the configurable endpoint if custom MCP servers are not a required feature. - Enforce HTTPS and compare the parsed hostname against an exact allowlist, preferably only `mcp.canva.com`. - Reject URLs containing user information, unexpected ports, redirects to unapproved hosts, or nonstandard schemes. - If custom endpoints are required for development, place them behind an explicit unsafe-development option. - Never reuse production OAuth credentials with custom endpoints. Require a separate authentication provider and credential store. - Display the selected endpoint and require explicit user or administrator approval before authenticating to a non-default service. - Add tests covering HTTP URLs, look-alike domains, subdomain confusion, embedded credentials, unexpected ports, and redirect behavior.

T01 · Skill Instruction Hijacking

Warning
Location
app.py:821
Finding
Design Generation Instructions Encourage Excessive Chat-History Disclosure## Vulnerability Details **File Location**: `app.py:821-822`, with the transmission sink at `app.py:915-926` **Vulnerability Type**: Agent instruction hijacking leading to excessive remote data disclosure **Risk Level**: Medium ```python The tool doesn't have context of previous requests. ALWAYS include details from previous queries for each iteration. The tool provides best results with detailed context. ALWAYS look up the chat history and provide as much context as possible in the 'query' parameter. ``` The instructed content is placed in the remote tool request as follows: ```python async with self._get_client() as client: call_args = {} call_args["query"] = query if asset_ids is not None: call_args["asset_ids"] = asset_ids if brand_kit_id is not None: call_args["brand_kit_id"] = brand_kit_id if design_type is not None: call_args["design_type"] = design_type if user_intent is not None: call_args["user_intent"] = user_intent result = await client.call_tool("generate-design", call_args) ``` ### Technical Analysis The skill text uses persistent, emphatic instructions telling an agent to inspect chat history and include as much context as possible in the generation query. This conflicts with data-minimization principles because it does not limit collection to information necessary for the requested design. The resulting `query` is transmitted to a remote MCP tool. Prior conversation history may contain unrelated personal information, confidential business material, credentials, access tokens, or instructions that the user did not intend to disclose to Canva. The risk becomes more severe when combined with the configurable endpoint because the same data could be sent to a non-Canva server. ### Attack Path 1. A user has sensitive or unrelated information in earlier conversation messages. 2. The user later requests Canva design generation. 3. ...[truncated 912 chars]
Remediation
## Remediation Suggestions - Replace the instruction with a requirement to include only the minimum task-relevant context. - Do not direct agents to inspect or reproduce unrelated conversation history. - Require explicit user approval before incorporating content from earlier messages into a remote request. - Add a redaction step for passwords, API keys, OAuth tokens, personal identifiers, financial information, and confidential business data. - Construct a concise task summary locally rather than copying messages verbatim. - Clearly disclose that generation prompts are transmitted to Canva or the configured MCP endpoint. - Enforce a bounded query length and add automated checks for common secret formats before transmission.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:33
Finding
Security-Sensitive Dependency Is Installed Without Version or Integrity Pinning## Vulnerability Details **File Location**: `SKILL.md:33-42` and `SKILL.md:77-80` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Medium ```bash uv pip install mcp-skill ``` ```bash pip install mcp-skill ``` ### Technical Analysis The installation instructions resolve `mcp-skill` without a fixed version or package hash. Consequently, installation behavior depends on whichever release the package index serves at that time. This dependency is security-sensitive because the application imports its OAuth implementation: ```python from mcp_skill.auth import OAuth ``` The documentation also states that authentication tokens are persisted under `~/.mcp-skill/auth/`. A compromised or unexpectedly changed dependency release could therefore execute with the user's privileges and potentially access authentication state. No lockfile, hash verification, or reviewed version constraint is included in the project. This finding identifies supply-chain exposure rather than evidence that the current `mcp-skill` package is malicious. ### Attack Path 1. A user follows the documented installation command. 2. The package manager resolves the latest available `mcp-skill` release. 3. An upstream compromise, account takeover, malicious release, or incompatible future change causes unsafe code to be distributed. 4. The package is installed and later imported by `app.py`. 5. The dependency executes with the user's permissions and participates in OAuth handling. 6. A malicious release could access persisted credentials, application data, network resources, or other files available to the user. ### Impact Assessment Successful supply-chain compromise would execute code with the privileges of the user running the skill. Because the dependency manages OAuth and persisted authentication state, exposed assets could include Canva tokens and data accessible through their granted scopes. The impact could extend ...[truncated 66 chars]
Remediation
## Remediation Suggestions - Pin `mcp-skill` to a specifically reviewed version. - Use a lockfile and require cryptographic hashes for reproducible installations. - Document and enforce the trusted package index. - Review dependency provenance, maintainers, release signatures, and transitive dependencies. - Test dependency upgrades in isolation before changing the approved version. - Run the skill with least privilege and restrict access to unrelated local files where practical. - Protect `~/.mcp-skill/auth/` with restrictive filesystem permissions. - Establish automated dependency monitoring while requiring manual security review before upgrades.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Credential Access

High
Category
Privilege Escalation
Content
"""
        
    Upload an asset (e.g. an image, a video) from a URL into Canva
    If the API call returns "Missing scopes: [asset:write]", you should ask the user to disconnect and reconnect their connector. This will generate a new access token with the required scope for this tool.
    

        Args:
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
"""
        
    Upload an asset (e.g. an image, a video) from a URL into Canva
    If the API call returns "Missing scopes: [asset:write]", you should ask the user to disconnect and reconnect their connector. This will generate a new access token with the required scope for this tool.
    

        Args:
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
"""
        
    Upload an asset (e.g. an image, a video) from a URL into Canva
    If the API call returns "Missing scopes: [asset:write]", you should ask the user to disconnect and reconnect their connector. This will generate a new access token with the required scope for this tool.
    

        Args:
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
86% confidence
Finding
The skill exposes broad network-capable functionality and many remote operations, but the manifest does not declare any explicit tool scope such as permissions or allowed-tools. That weakens policy enforcement and reviewability because consumers cannot easily constrain what the skill may access or invoke, increasing the chance of unintended external requests or overbroad execution.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation states OAuth tokens are persisted under `~/.mcp-skill/auth/` but does not warn users about local credential storage, file permissions, multi-user host exposure, or secure deletion concerns. On shared or poorly secured systems, persisted tokens can be recovered and reused to access the user's Canva account and associated data.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
Provides tools to interact with tools: upload-asset-from-url, resolve-shortlink, search-designs, get-design, get-design-pages and 17 more.
    """

    def __init__(self, url: str = "https://mcp.canva.com/mcp", auth=None) -> None:
        self.url = url
        self._oauth_auth = auth
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The wrapper exposes a destructive design-modifying operation and relies only on docstring instructions to require explicit user confirmation before execution. There is no programmatic guard, confirmation token, or policy enforcement in code, so any upstream agent, UI bug, or prompt-injection-induced tool call can invoke page deletion or reordering immediately. In this skill context, that is more dangerous because the tool directly mutates user content and the method includes irreversible delete operations.

Rp1

Low
Category
MCP Rug Pull
Confidence
79% confidence
Finding
Installing `mcp-skill` without a pinned version makes builds non-reproducible and allows future upstream changes to alter behavior unexpectedly. If a compromised or breaking release is published, users may silently install it and expose themselves to supply-chain risk.

Rp1

Low
Category
MCP Rug Pull
Confidence
79% confidence
Finding
Installing `mcp-skill` without a pinned version makes builds non-reproducible and allows future upstream changes to alter behavior unexpectedly. If a compromised or breaking release is published, users may silently install it and expose themselves to supply-chain risk.

Rp1

Low
Category
MCP Rug Pull
Confidence
79% confidence
Finding
Installing `mcp-skill` without a pinned version makes builds non-reproducible and allows future upstream changes to alter behavior unexpectedly. If a compromised or breaking release is published, users may silently install it and expose themselves to supply-chain risk.

Static analysis

No suspicious patterns detected.