Back to skill

Security audit

Coda

Security checks for vulnerabilities and agentic risk

Overview

This Coda skill is mostly purpose-aligned, but it needs review because it can change or delete Coda data and has safety and credential-handling gaps.

Install only if you are comfortable giving the skill access to the Coda documents available to your token. Prefer CODA_API_TOKEN over --token, avoid --force unless you are deliberately automating deletion, and verify destructive or mutating commands carefully because retries may repeat some operations.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/coda_cli.py:403
Finding
API Token Exposure Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/coda_cli.py`, lines 50–60, 403, and 544 **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python def __init__(self, token: Optional[str] = None): self.token = token or os.environ.get("CODA_API_TOKEN") if not self.token: raise CodaAPIError( "Coda API token required. Set CODA_API_TOKEN environment variable " "or pass --token." ) if HAS_REQUESTS: self.session = requests.Session() self.session.headers.update({ "Authorization": f"Bearer {self.token}", "Content-Type": "application/json" }) ``` ```python parser.add_argument("--token", help="Coda API token") ``` ```python client = CodaClient(token=args.token) ``` ### Technical Analysis The CLI explicitly permits a Coda API token to be supplied using the `--token` command-line option. Command-line arguments are commonly exposed through: - Shell history files - Process inspection tools such as `ps` - Process accounting and operating-system audit logs - CI/CD execution logs - Terminal recordings and support diagnostics - Parent-process telemetry or endpoint-monitoring products The token is subsequently used as a Bearer credential for the Coda API. Although transmitting that credential to the fixed official HTTPS endpoint is necessary for the declared functionality, accepting it through a command-line argument creates unnecessary local exposure. The documented `CODA_API_TOKEN` environment-variable mechanism already provides an alternative, so the command-line credential path exceeds the minimum interface required. ### Attack Path 1. A user invokes the tool with a command such as: ```bash python scripts/coda_cli.py --token SECRET docs list ``` 2. The complete command is retained in shell history, captured in automation logs, or temporarily exposed through the process ...[truncated 963 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--token` argument and accept credentials only through `CODA_API_TOKEN` or a protected credential provider. 2. For interactive use, retrieve the token with `getpass.getpass()` so it is not echoed or recorded in shell history. 3. Consider operating-system credential stores or a configuration file with owner-only permissions. 4. If backward compatibility requires `--token`, display a prominent security warning and deprecate the option. 5. Ensure CI/CD systems inject the token through masked secret variables and do not print the environment. 6. Recommend narrowly scoped or dedicated Coda credentials where the platform supports them. 7. Document immediate token revocation and rotation procedures for suspected exposure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/coda_cli.py:73
Finding
Automatic Retries Can Duplicate Non-Idempotent API Mutations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/coda_cli.py`, lines 73–74 and 80–131 **Vulnerability Type**: Unsafe retry of non-idempotent network operations **Risk Level**: Medium ### Vulnerable Code ```python max_retries = 3 retry_delay = 1 ``` ```python for attempt in range(max_retries): try: if HAS_REQUESTS: response = self.session.request( method, url, json=json_data ) status_code = response.status_code text = response.text else: # Fallback to urllib req = urllib.request.Request( url, data=json.dumps(json_data).encode() if json_data else None, headers={ "Authorization": f"Bearer {self.token}", "Content-Type": "application/json" }, method=method ) try: with urllib.request.urlopen(req) as resp: status_code = resp.status text = resp.read().decode() except urllib.error.HTTPError as e: status_code = e.code text = e.read().decode() # Handle rate limiting (429) if status_code == 429: if attempt < max_retries - 1: time.sleep(retry_delay) retry_delay *= 2 continue raise CodaAPIError("Rate limit exceeded. Please wait and try again.") # Handle other errors if status_code >= 400: try: error_data = json.loads(text) message = error_data.get("message", "Unknown error") except: message = text or "Unknown error" if status_code == 401: raise CodaAPIError(f"Authentication failed: {message}") elif status_code == 403: raise CodaAPIError(f"Permission denied: {message}") el ...[truncated 3234 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Retry only safe or naturally idempotent requests by default, particularly `GET`. 2. Do not automatically retry `POST`, `PATCH`, or other mutations after ambiguous transport failures. 3. Where supported by the Coda API, attach a unique idempotency key to each mutation and reuse it only for retries of that logical operation. 4. For asynchronous operations, preserve the returned request identifier and query operation status rather than resubmitting the mutation. 5. Catch transport exceptions explicitly, such as `requests.ConnectionError`, `requests.Timeout`, and corresponding `urllib` exceptions. 6. Allow `CodaAPIError`, JSON decoding errors, and permanent HTTP failures to propagate without retrying. 7. Retry HTTP 429 responses only when appropriate, honoring the server's `Retry-After` header. 8. Define method-specific retry policies and add tests simulating a server commit followed by a lost response. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code is clearly a Coda API CLI and broadly aligns with the Coda resource domain, token requirement, and deletion confirmation behavior. However, the declared description overstates implemented functionality in several material areas. The code supports docs (list/get/create/delete), rows (list/insert/update/delete), and read-only listing of tables and pages. It does not implement automation triggers, publishing, permission changes, or full CRUD management for tables/pages despite the description claiming those capabilities. This is a description-to-behavior mismatch because the declared functional scope is materially broader than what the code actually does.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares access to environment variables and network-reachable API operations, but does not define any explicit tool scope such as allowed-tools or permissions. This creates an authorization and review gap: an agent may use sensitive capabilities like reading CODA_API_TOKEN and making outbound requests without clear policy constraints, increasing the chance of unintended data access or exfiltration.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Trigger automation (push button)
python scripts/coda_cli.py automations trigger <doc-id> <button-id>

# Force delete without confirmation (use with caution)
python scripts/coda_cli.py docs delete <doc-id> --force
```
Confidence
88% confidence
Finding
The skill explicitly documents a force-delete path that bypasses confirmation for destructive operations. In an agent context, exposing an unauthenticated or loosely gated `--force` workflow increases the risk of irreversible deletion of docs or data due to prompt injection, user ambiguity, or autonomous execution without meaningful human verification.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"""
    )
    parser.add_argument("--token", help="Coda API token")
    parser.add_argument("--force", action="store_true", help="Skip confirmations")
    
    subparsers = parser.add_subparsers(dest="cmd_group")
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"""
    )
    parser.add_argument("--token", help="Coda API token")
    parser.add_argument("--force", action="store_true", help="Skip confirmations")
    
    subparsers = parser.add_subparsers(dest="cmd_group")
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"""
    )
    parser.add_argument("--token", help="Coda API token")
    parser.add_argument("--force", action="store_true", help="Skip confirmations")
    
    subparsers = parser.add_subparsers(dest="cmd_group")
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Static analysis

No suspicious patterns detected.