Back to skill

Security audit

Canva

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Canva integration, but it uses broad Canva OAuth access and stores tokens locally with weak handling plus an unpinned installer instruction.

Review this before installing if you use Canva for private or business assets. Pin the installer version, restrict token file permissions, consider a secret manager instead of plaintext `~/.canva/tokens.json`, and only allow uploads or exports for files and designs you explicitly choose.

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

T08 · Insecure Dependencies

Warning
Location
README.md:15
Finding

Unpinned Package Installer Executes a Mutable Dependency

Content
View full analysis

Vulnerability Details

File Location: README.md, lines 15-17
Vulnerability Type: T08: Insecure Dependencies
Risk Level: Medium

Vulnerable Code:

bash
npx clawdhub@latest install canva

Technical Analysis

The documented installation command instructs npx to retrieve and execute the current latest release of the clawdhub package. The latest tag is mutable and does not identify a specific audited artifact. Consequently, the code executed by this command can change after the Skill itself has been reviewed.

Because package installation tools can execute package entry points and lifecycle scripts, a compromised maintainer account, registry package, or future release could cause arbitrary code to run under the installing user's account. No malicious dependency is present in the audited project itself; the risk arises from the unsafe, unpinned installation instruction.

Attack Path

  1. An attacker compromises the package registry account, package publication process, or a future release of clawdhub.
  2. The attacker publishes a modified version and assigns it to the mutable latest tag.
  3. A user follows the installation command from README.md.
  4. npx downloads and executes the attacker-controlled package version.
  5. Malicious package code runs with the privileges and environment available to the user performing the installation.

Impact Assessment

Successful exploitation could provide arbitrary code execution with the installing user's privileges. Depending on that user's access, the malicious package could read personal files and environment variables, steal credentials, modify user-owned files, or install additional software. It would not inherently grant root privileges unless the command were run by a privileged user or combined with another escalation mechanism.

Remediation
View remediation

Remediation Suggestions

  • Replace @latest with an exact, reviewed package version.
  • Where supported, verify the package against a trusted integrity hash or signed provenance record.
  • Document the expected publisher, version, and checksum so users can validate the downloaded artifact.
  • Prefer a trusted installer already present on the system rather than allowing npx to retrieve executable code implicitly.
  • Review release artifacts before updating the documented version.
  • Avoid recommending execution as root or through sudo.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/canva-auth.sh:12
Finding

OAuth Tokens Are Not Written with Secure Permissions Atomically

Content
View full analysis

Vulnerability Details

File Location: scripts/canva-auth.sh, lines 12-13, 29, and 81-82
Vulnerability Type: T09: Insecure Skill Coding Practices
Risk Level: Medium

Vulnerable Code:

bash
TOKEN_FILE="$HOME/.canva/tokens.json"
mkdir -p "$HOME/.canva"
bash
if echo "$RESPONSE" | jq -e '.access_token' > /dev/null 2>&1; then
    echo "$RESPONSE" > "$TOKEN_FILE"
    echo "✅ Token refreshed successfully!"
    echo "Access token saved to: $TOKEN_FILE"
    exit 0
bash
if echo "$RESPONSE" | jq -e '.access_token' > /dev/null 2>&1; then
    echo "$RESPONSE" > "$TOKEN_FILE"
    chmod 600 "$TOKEN_FILE"

Technical Analysis

The token directory is created without explicitly enforcing mode 0700. Its resulting permissions therefore depend on the user's current umask or the permissions of a pre-existing directory.

During initial authentication, the OAuth response is written to tokens.json before chmod 600 is applied. With a permissive umask, the file can briefly be readable by other local users. This creates a time-of-check/time-of-permission race in which another local process may open the file before its mode is restricted.

The refresh path writes the new OAuth response but never reapplies chmod 600. Shell redirection preserves the permissions of an existing file, so an already over-permissive token file remains exposed after refresh. The OAuth response can contain both an access token and a refresh token, making disclosure security-sensitive.

Attack Path

  1. A victim runs canva-auth.sh on a multi-user system with a permissive umask, or a token file already exists with overly broad permissions.
  2. The script creates or overwrites ~/.canva/tokens.json without first guaranteeing restrictive file permissions.
  3. A malicious local user or process monitors the directory and opens the token file while it is readable, or reads it later when the refre ...[truncated 966 chars]
Remediation
View remediation

Remediation Suggestions

  • Set a restrictive process mask before creating any credential-bearing files:

    bash
    umask 077
    
  • Create and repair the credential directory with explicit permissions:

    bash
    install -d -m 700 "$HOME/.canva"
    
  • Write tokens to a securely created temporary file in the same directory, set mode 600, and atomically rename it:

    bash
    TEMP_FILE=$(mktemp "$HOME/.canva/tokens.json.XXXXXX")
    chmod 600 "$TEMP_FILE"
    printf '%s\n' "$RESPONSE" > "$TEMP_FILE"
    mv -f "$TEMP_FILE" "$TOKEN_FILE"
    
  • Apply the same secure write routine to both initial authentication and token refresh.

  • Validate that ~/.canva and tokens.json are owned by the current user and are not symbolic links before writing.

  • Consider storing OAuth credentials in the operating system's credential manager instead of a plaintext JSON file.

  • Revoke and regenerate tokens if existing files may have been readable by other users.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The description focuses on design creation and management, but the documented behavior also includes reading OAuth tokens from a local file and uploading binary assets to a third-party service. That mismatch can mislead users about credential access and data exfiltration risks, reducing informed consent for sensitive actions.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The skill instructs users to obtain and store access tokens locally, creating a credential exposure point. OAuth bearer tokens can grant direct access to Canva resources, so insecure storage or accidental disclosure can lead to unauthorized account access and data operations.

Content

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

text

3. **Authenticate (first time):**
   Run the auth flow to get access tokens (stored in `~/.canva/tokens.json`)

## API Base URL

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The command explicitly reads the bearer access token from ~/.canva/tokens.json into a shell variable, normalizing direct credential access in a shell context. This increases the chance of token leakage through logs, shell history, process inspection, debugging output, or accidental reuse.

Content

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

Canva uses OAuth 2.0. The skill handles token refresh automatically.

bash
# Get access token (stored in ~/.canva/tokens.json)
ACCESS_TOKEN=$(cat ~/.canva/tokens.json | jq -r '.access_token')

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/canva-auth.sh (reported line 20)May include surrounding context.

sh
REFRESH_TOKEN=$(jq -r '.refresh_token // empty' "$TOKEN_FILE" 2>/dev/null)
    
    if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

After refreshing tokens, the script writes the response to the token file but does not set restrictive permissions in that code path. If the file is newly created or existing permissions are too broad, other local users may be able to read refresh or access tokens, enabling unauthorized API access.

Content

Scanner excerpt · scripts/canva-auth.sh (reported line 32)May include surrounding context.

sh
if echo "$RESPONSE" | jq -e '.access_token' > /dev/null 2>&1; then
            echo "$RESPONSE" > "$TOKEN_FILE"
            echo "✅ Token refreshed successfully!"
            echo "Access token saved to: $TOKEN_FILE"
            exit 0
        else
            echo "⚠️ Refresh failed, need to re-authenticate"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README advertises listing designs, creating from templates, exporting, uploading assets, and accessing brand templates, but it does not clearly warn users that local content and account data will be transmitted to Canva and that remote account state may be changed. This omission can lead users to unknowingly expose sensitive files, branding assets, or design metadata to a third-party service through the skill.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · README.md (reported line 8)May include surrounding context.

md
## Features

- 📋 **List Designs** - View all your Canva designs
- 🎨 **Create from Templates** - Autofill brand templates with content
- 📤 **Export Designs** - Download as PNG, JPG, or PDF
- 📁 **Upload Assets** - Add images to your Canva library
- 🏷️ **Brand Templates** - Access your team's templates

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The README instructs users to run npx clawdhub@latest install canva, which fetches and executes whatever code is currently published under that package name at install time. Because the version is not pinned, users are exposed to supply-chain risk from a compromised publisher account, malicious new release, or unexpected breaking change that could execute arbitrary code during installation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The natural-language examples are broad (Show me my Canva designs, Upload this image to Canva) and do not communicate scope limits, confirmation requirements, or safety boundaries for actions that read account data or modify remote assets. In an agent setting, vague invocation guidance can encourage overbroad tool use, unintended account access, or remote side effects without clear user intent verification.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents shell-based behavior but does not declare any explicit tool scope or allowed tools. That weakens the trust boundary for users and hosts because commands that access local files and remote APIs may be available without clear permission disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill encourages uploading images and exporting/downloading designs without clearly warning that user content will be transmitted to Canva and files may be created or retrieved locally. Users may unknowingly send sensitive media or generate local artifacts without understanding the privacy implications.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

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

md
## When to Use

- "Create an Instagram post about [topic]"
- "Export my Canva design as PNG"
- "List my recent designs"
- "Create a carousel from these points"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation states that OAuth tokens are stored in ~/.canva/tokens.json and shows how to read them, but it does not warn users about local credential storage risks. Exposing token locations makes accidental disclosure, theft, or insecure file permissions more likely.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 71)May include surrounding context.

Create Design from Template

bash
curl -X POST "https://api.canva.com/rest/v1/autofills" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

External Transmission

Medium
Category
Data Exfiltration
Confidence
83% confidence
Finding

The asset upload endpoint can transfer local binary content to Canva, which is a real privacy and data-loss concern if used without explicit consent. In a shell-capable skill, file-upload behavior deserves stronger controls than generic API communication.

Content

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

Upload Asset

bash
curl -X POST "https://api.canva.com/rest/v1/asset-uploads" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  -H 'Asset-Upload-Metadata: {"name": "my-image.png"}' \

External Transmission

Medium
Category
Data Exfiltration
Confidence
83% confidence
Finding

The asset upload endpoint can transfer local binary content to Canva, which is a real privacy and data-loss concern if used without explicit consent. In a shell-capable skill, file-upload behavior deserves stronger controls than generic API communication.

Content

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

Upload Asset

bash
curl -X POST "https://api.canva.com/rest/v1/asset-uploads" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  -H 'Asset-Upload-Metadata: {"name": "my-image.png"}' \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 40)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 57)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 64)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 71)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 87)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 96)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 113)May include surrounding context.

md
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/canva-auth.sh (reported line 22)May include surrounding context.

sh
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/canva-auth.sh (reported line 71)May include surrounding context.

sh
if [ -n "$REFRESH_TOKEN" ]; then
        echo "🔄 Refreshing access token..."
        
        RESPONSE=$(curl -s -X POST "https://api.canva.com/rest/v1/oauth/token" \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "grant_type=refresh_token" \
            -d "client_id=$CANVA_CLIENT_ID" \

Static analysis

No suspicious patterns detected.