Back to skill

Security audit

ChatDOC Studio API

Security checks for vulnerabilities and agentic risk

Overview

This is mostly transparent API documentation, but it includes an unsafe bulk app-deletion example and limited privacy guidance for uploaded documents.

Install only if you are comfortable using ChatDOC Studio as an external document-processing service. Do not run the bulk app cleanup example as written; require a dry run, explicit app ID allowlist, backups, and confirmation before any DELETE call. Avoid uploading confidential, regulated, or customer documents unless your organization has approved ChatDOC Studio's handling, retention, and access controls for that data.

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

Warning
Location
apps/apps_examples.md:295
Finding
Unattended Irreversible Bulk Deletion of Applications<![CDATA[ ## Vulnerability Details **File Location**: `apps/apps_examples.md`, lines 295–305; equivalent TypeScript workflow at lines 329–337 **Vulnerability Type**: Unsafe destructive operation without confirmation or dry-run safeguards **Risk Level**: Medium ### Vulnerable Code ```python # 3. Delete old apps (example: delete apps created more than 90 days ago) import time current_time = int(time.time()) ninety_days_ago = current_time - (90 * 24 * 60 * 60) for app in result["items"]: if app["created_at"] < ninety_days_ago: print(f"Deleting old app: {app['name']} (ID: {app['id']})") try: delete_app(app["id"]) except Exception as e: print(f"Failed to delete {app['id']}: {e}") ``` The equivalent TypeScript workflow is: ```typescript // 3. Delete old apps (example: delete apps created more than 90 days ago) const currentTime = Math.floor(Date.now() / 1000); const ninetyDaysAgo = currentTime - (90 * 24 * 60 * 60); for (const app of result.items) { if (app.created_at < ninetyDaysAgo) { console.log(`Deleting old app: ${app.name} (ID: ${app.id})`); try { await deleteApp(app.id); } catch (error) { console.error(`Failed to delete ${app.id}:`, error); } } } ``` ### Technical Analysis The example performs an irreversible API deletion for every application in the returned page whose creation timestamp is older than 90 days. The underlying documentation states that deletion permanently removes the application and may also remove associated versions, conversations, or Agent task records. Although application management and deletion are declared Skill capabilities, presenting automatic deletion as part of a complete workflow is an unsafe default. The code provides no dry-run mode, interactive confirmation, explicit allowlist, backup verification, ownership validation beyond server-side authorization, or separate opt-in flag. Age alone is not a reliable indication that an application i ...[truncated 1612 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make the workflow dry-run-only by default and print the application IDs, names, types, and creation dates that would be deleted. 2. Require an explicit destructive flag such as `--confirm-delete` before issuing any `DELETE` request. 3. Require confirmation for each application or accept a user-supplied allowlist of exact application IDs. 4. Do not treat age as sufficient authorization to delete. Add filters for application type, owner, environment, labels, or an explicit archival marker. 5. Require the user to type a confirmation phrase containing the team or application ID for bulk operations. 6. Verify backups or exports before deleting applications with associated conversations or task records. 7. Separate the destructive cleanup example from the normal list-and-filter workflow and place a prominent irreversible-operation warning immediately before executable code. 8. Prefer a two-phase lifecycle—archive or disable first, then delete after a retention period—if supported by the service. 9. Record an audit log of selected targets and API responses without logging bearer credentials or sensitive document content. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
chat/chat_app_examples.md:586
Finding
Predictable Shared Temporary File in Chat App Publishing Script<![CDATA[ ## Vulnerability Details **File Location**: `chat/chat_app_examples.md`, lines 586–607 **Vulnerability Type**: Insecure temporary-file creation and time-of-check/time-of-use exposure **Risk Level**: Low ### Vulnerable Code ```bash # Poll for completion (in a script) for i in {1..30}; do HTTP_CODE=$(curl -s -o /tmp/publish_resp.json -w "%{http_code}" -X POST "${CHATDOC_STUDIO_BASE_URL}/chat/apps/abc123/publish" \ -H "Authorization: Bearer ${CHATDOC_STUDIO_API_KEY}") ERROR_CODE=$(jq -r '.code // empty' /tmp/publish_resp.json) if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then echo "✓ App published!" break fi if [ "$ERROR_CODE" = "already_published" ]; then echo "✓ App already published!" break fi if [ "$ERROR_CODE" = "training" ]; then echo "Publishing... ($i/30)" sleep 2 continue fi echo "Publish failed: HTTP ${HTTP_CODE}, code=${ERROR_CODE:-unknown_error}" cat /tmp/publish_resp.json | jq '.' exit 1 done ``` ### Technical Analysis The script stores an API response at the fixed path `/tmp/publish_resp.json`. Shared temporary directories are normally writable by multiple local users. The script neither securely creates the file nor checks whether it is a regular file owned by the current user. It also leaves the response behind after execution. A local attacker may pre-create the path as a symbolic link to another file writable by the victim. When `curl -o` opens the path, it may follow the link and overwrite that target. An attacker may also race or replace the temporary response between the `curl` write and subsequent `jq` or `cat` reads, creating a time-of-check/time-of-use condition that influences control flow or displayed output. The response does not intentionally contain the bearer credential, but it may contain application identifiers, status details, or service error information. ### Attack Path 1. An attacker with access to the same host predicts the fixed path `/tmp/p ...[truncated 1273 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Use a securely generated temporary file, apply restrictive permissions, and guarantee cleanup: ```bash tmpfile=$(mktemp "${TMPDIR:-/tmp}/chatdoc-publish.XXXXXX") || exit 1 chmod 600 "$tmpfile" trap 'rm -f -- "$tmpfile"' EXIT HUP INT TERM for i in {1..30}; do HTTP_CODE=$(curl --fail-with-body -sS -o "$tmpfile" -w "%{http_code}" \ -X POST "${CHATDOC_STUDIO_BASE_URL}/chat/apps/abc123/publish" \ -H "Authorization: Bearer ${CHATDOC_STUDIO_API_KEY}") || { echo "Request failed" exit 1 } ERROR_CODE=$(jq -r '.code // empty' -- "$tmpfile") # Continue with status handling. done ``` Additional hardening measures: 1. Never use a constant filename in a shared temporary directory. 2. Quote all temporary-file variables and use `--` before filename arguments. 3. Remove the file through a shell `trap` on normal and abnormal termination. 4. Avoid printing the complete response unless needed, because error bodies may contain sensitive service metadata. 5. If practical, capture and parse the response in memory rather than through a filesystem intermediary. ]]>

T08 · Insecure Dependencies

Note
Location
parsers/pdf_parser_examples.md:50
Finding
Unpinned npm Dependency Installation Guidance<![CDATA[ ## Vulnerability Details **File Location**: `parsers/pdf_parser_examples.md`, line 50 **Vulnerability Type**: Mutable third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```typescript // npm i axios form-data import * as fs from 'node:fs'; import FormData from 'form-data'; import axios from 'axios'; ``` ### Technical Analysis The example recommends installing `axios` and `form-data` without specifying tested versions or requiring a lockfile. An unpinned `npm i` resolves package and transitive-dependency versions according to the registry state at installation time. The effective dependency graph can therefore change after the Skill has been reviewed. npm packages may define installation lifecycle scripts that execute with the operating-system privileges of the user running npm. If a future package release or transitive dependency is compromised, users following the example could install and execute malicious code. No evidence indicates that the named packages are malicious; the finding concerns mutable supply-chain resolution and the absence of reproducibility controls. ### Attack Path 1. A user follows the comment and runs `npm i axios form-data`. 2. npm queries the configured registry and resolves the latest versions permitted at that time, along with transitive dependencies. 3. A compromised future release, compromised maintainer account, malicious transitive dependency, or unsafe registry configuration supplies altered package content. 4. npm installs the package and may execute lifecycle scripts during installation. 5. Malicious package code executes with the installing user's privileges or is later imported by the PDF upload application. This path depends on an upstream or registry compromise; the audited project does not itself retrieve or execute a known malicious package. ### Impact Assessment A compromised dependency could obtain the same local privileges as the Node.js process or npm invocation. Depending on ...[truncated 510 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Specify versions tested with the examples, such as exact dependency versions rather than unconstrained latest releases. 2. Provide a reviewed `package.json` and committed lockfile. 3. Recommend `npm ci` for reproducible installation from the lockfile instead of ad hoc `npm i`. 4. Use lockfile integrity hashes and a trusted, explicitly configured npm registry. 5. Review dependency updates before regenerating the lockfile. 6. Run `npm audit` or an equivalent software-composition analysis tool as part of continuous integration. 7. Consider disabling lifecycle scripts during installation with `npm ci --ignore-scripts` when package functionality does not require them, followed by explicit review of any package that does. 8. Run installation and examples in a minimally privileged container or dedicated account without unrelated credentials. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (89)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
Delete an application by app_id. This operation permanently removes the app and all its associated data.

**Endpoint:** `DELETE /apps/{app_id}`

**Path Parameters:**
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Missing User Warnings

High
Confidence
97% confidence
Finding
The complete workflow automates bulk destructive behavior by iterating through apps and deleting those older than 90 days, yet it lacks a strong markdown warning or safeguards. In agentic settings, examples like this can be adapted into unattended jobs, leading to mass deletion and operational disruption.

Exfiltration Commands

High
Category
Prompt Injection
Content
- You need to **poll** this endpoint until it returns `201` (published successfully)
- During processing, the endpoint may return `400` with error code `training`; keep polling
- If you call publish again after successful publication, you'll get `already_published` error
- An app must be published before you can send messages to it

**Create/Update Notes**:
- `suggested_messages` can contain at most 3 items, and each item must be 50 characters or fewer.
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Exfiltration Commands

High
Category
Prompt Injection
Content
- You need to **poll** this endpoint until it returns `201` (published successfully)
- During processing, the endpoint may return `400` with error code `training`; keep polling
- If you call publish again after successful publication, you'll get `already_published` error
- An app must be published before you can send messages to it

**Create/Update Notes**:
- `suggested_messages` can contain at most 3 items, and each item must be 50 characters or fewer.
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Exfiltration Commands

High
Category
Prompt Injection
Content
- You need to **poll** this endpoint until it returns `201` (published successfully)
- During processing, the endpoint may return `400` with error code `training`; keep polling
- If you call publish again after successful publication, you'll get `already_published` error
- An app must be published before you can send messages to it

**Create/Update Notes**:
- `suggested_messages` can contain at most 3 items, and each item must be 50 characters or fewer.
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

External Transmission

Medium
Category
Data Exfiltration
Content
console.log(`Task status: ${task.status}`);
```

### cURL

```bash
curl -X POST "${CHATDOC_STUDIO_BASE_URL}/agent/apps/tasks" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The file is presented as a usage guide for parsing/chat/retrieval/extraction APIs, but it also includes destructive administrative operations for deleting apps and lifecycle management. In a skill context, this broadens capability beyond the stated purpose and can mislead downstream agents or users into invoking irreversible actions they did not expect.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Destructive deletion workflows are included in markdown examples without prominent safety framing in the surrounding documentation. Users often copy examples directly; without warnings, the examples normalize irreversible actions and increase the risk of accidental execution.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The cURL delete example is directly executable and omits an inline warning that it permanently deletes the specified app. Because cURL snippets are frequently pasted verbatim, the absence of safety notes materially increases the risk of accidental destructive use.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The workflow demonstrates bulk deletion of apps based solely on age, which is an unsafe destructive pattern that can delete valid production assets without human review. Providing turnkey automation for irreversible deletion increases the chance that an agent or operator will run it as-is and cause large-scale accidental loss.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation encourages binding documents and enabling source tracing without warning that quoted passages, snippets, or metadata from uploaded documents may be surfaced to end users. In a document-Q&A application, this can unintentionally disclose confidential content if developers attach sensitive files or enable tracing in broadly accessible apps.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill documents creation, listing, and retrieval of conversations and full message histories but does not warn that these endpoints expose potentially sensitive user prompts, model outputs, and persistent conversation data. In an agent skill context, omission of privacy guidance can lead downstream integrators to enable logging, retention, or display of chat history without user consent or access controls.

External Transmission

Medium
Category
Data Exfiltration
Content
}
```

### cURL

```bash
# Customer Service App
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The messaging and conversation examples transmit user prompts, conversation identifiers, and retrieved dialogue content to a third-party API, but the documentation does not warn users about privacy, retention, or sensitive-data handling. In an agent skill context, this omission can cause developers to unknowingly route confidential user or document data off-platform.

External Transmission

Medium
Category
Data Exfiltration
Content
console.log(`Answer: ${result.answer}`);
```

### cURL

```bash
# Send message with conversation_id
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation instructs users to upload documents for extraction but does not warn that full document contents may be transmitted to and processed by an external service. In a document-processing API, this omission can lead users to submit sensitive PDFs, contracts, or personal data without understanding the privacy, compliance, or data-handling implications.

External Transmission

Medium
Category
Data Exfiltration
Content
}
```

### cURL

```bash
curl -X POST "${CHATDOC_STUDIO_BASE_URL}/extract/apps" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The examples encourage uploading local files such as `invoice.pdf` to a remote service without warning that document contents will leave the local environment. In a document-extraction context, those files may contain sensitive financial, personal, or regulated data, so omission of a privacy/transmission warning can lead to unintended data disclosure.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The documentation presents `extract-again` as a `GET` request even though it triggers server-side reprocessing, which is a state-changing action. Using GET for side effects increases the chance of accidental invocation by link prefetchers, crawlers, caches, or automated tooling that assumes GET is safe and idempotent.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documentation instructs users to upload PDF files and retrieve parsed content from a remote API, but it does not clearly disclose that full document contents may be transmitted to and processed by an external service. This can lead users to submit sensitive or regulated documents without understanding the privacy, confidentiality, or compliance implications.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The examples explicitly upload local PDF files to a third-party remote API but do not warn users that document contents leave the local system and may include sensitive or regulated data. In documentation for file-processing APIs, omission of a clear data-transmission notice can cause unintended disclosure when users test with confidential documents.

External Transmission

Medium
Category
Data Exfiltration
Content
import os
import requests

BASE_URL = os.getenv("CHATDOC_STUDIO_BASE_URL", "https://api.chatdoc.studio/v1")
API_KEY = os.getenv("CHATDOC_STUDIO_API_KEY")

def upload_pdf(file_path: str, wait: bool = False) -> dict:
Confidence
88% confidence
Finding
This code example defaults to a remote API endpoint and is used by an upload function that sends a local PDF to an external service. In context, the risk is not the URL string itself but that the example operationalizes off-system transmission without an adjacent privacy or sensitivity warning.

External Transmission

Medium
Category
Data Exfiltration
Content
import FormData from 'form-data';
import axios from 'axios';

const BASE_URL = process.env.CHATDOC_STUDIO_BASE_URL || 'https://api.chatdoc.studio/v1';
const API_KEY = process.env.CHATDOC_STUDIO_API_KEY || '';

interface UploadResponse {
Confidence
88% confidence
Finding
This TypeScript example hardcodes a remote default endpoint and is part of a file upload flow that transmits PDF content externally. Without disclosure in the surrounding docs, users may unknowingly expose sensitive documents during testing or integration.

External Transmission

Medium
Category
Data Exfiltration
Content
use reqwest::Client;
use serde::Deserialize;

const BASE_URL: &str = "https://api.chatdoc.studio/v1";

#[derive(Debug, Deserialize)]
struct UploadData {
Confidence
87% confidence
Finding
This Rust example embeds the external API base URL and is used in code that reads and uploads a local PDF to a remote server. The danger is unintended disclosure of document contents if users run the sample with real files without understanding the remote-processing model.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The retrieval API documentation describes sending arbitrary user queries and returning document-derived content, but it does not warn users that both query text and retrieved document content are transmitted to the external API service. This can cause developers to unintentionally send sensitive personal, proprietary, or regulated data off-platform, creating privacy, confidentiality, and compliance risk.

Static analysis

No suspicious patterns detected.