T09 · Insecure Skill Coding Practices
- Location
scripts/ghost.py:127- Finding
Arbitrary Remote Image Retrieval Enables SSRF and Internal Data Relay
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Ghost CMS skill does what it says, but it grants live blog admin powers and has under-scoped safeguards around credentials, publishing/deletion, API destinations, and remote image fetching.
Install only if you trust the publisher and need agent-assisted Ghost administration. Use a dedicated low-privilege Ghost integration if possible, keep the config file out of version control with restrictive permissions, require explicit human confirmation before publishing or deleting, use only HTTPS Ghost API URLs, and avoid passing untrusted remote feature-image URLs.
scripts/ghost.py:127Arbitrary Remote Image Retrieval Enables SSRF and Internal Data Relay
scripts/ghost.py:144Predictable Temporary File Creation Allows Symlink-Based File Overwrite
scripts/ghost.py:38Unvalidated API URL Can Transmit Ghost Administrative Tokens over Plaintext HTTP
SKILL.md:77Unpinned Runtime Dependencies Create Supply-Chain and Reproducibility Risk
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
Referenced artifact was not completely inspected
python3 scripts/ghost.py list --config "../../projects/fuye/ghost-admin.config.json"
This finding is a duplicate detection of the same issue: the documentation directs users to store the Ghost Admin API key in a JSON config file under a stable project path. That persistence model exposes an administrative secret to unintended disclosure and subsequent unauthorized post creation, modification, or deletion if the file is accessed by another party or tool.
3. Click **"Add custom integration"**
4. Copy the **Admin API Key** (format: `id:secret`)
### 2. Create Configuration File
**唯一调用方式:自定义配置文件路径(项目隔离)**
This finding is a duplicate detection of the same issue: the documentation directs users to store the Ghost Admin API key in a JSON config file under a stable project path. That persistence model exposes an administrative secret to unintended disclosure and subsequent unauthorized post creation, modification, or deletion if the file is accessed by another party or tool.
3. Click **"Add custom integration"**
4. Copy the **Admin API Key** (format: `id:secret`)
### 2. Create Configuration File
**唯一调用方式:自定义配置文件路径(项目隔离)**
The examples show immediate publishing with status set to published, but do not warn that content becomes publicly visible right away. In a content-management skill, this can lead to accidental disclosure of draft, sensitive, or unreviewed material through automation.
The skill documents deletion of Ghost posts without any warning, confirmation step, or guidance to verify the target post before execution. In an agentic context, this increases the chance of accidental irreversible content loss if a user request is ambiguous or the wrong post ID is supplied.
The documentation contains a real-looking Ghost Admin API key in an environment-variable example. Even if intended as a placeholder, publishing credential-shaped secrets normalizes unsafe secret handling and may result in users copying sensitive values into files or, if the token is real, immediate compromise of the Ghost admin interface.
The documentation provides a delete command example with no warning, confirmation guidance, or mention of irreversibility. In an agent or automation context, this increases the chance of accidental destructive actions against live content, especially if users or downstream tools treat examples as safe defaults.
User-facing descriptions and runtime messages are consistently presented in Chinese, including the module description and CLI output, with no opt-in or alternative locale support. This creates a natural-language policy concern when a skill imposes a specific language on users without documented justification.
The docstring states the '唯一方式' is a custom config file path for project isolation, reinforced again in CLI help and errors. In practice, get_config simply expands and opens whatever path the caller supplies, with no restriction to a project directory or any isolation boundary, so the documentation overstates the safety/constraint actually enforced by code.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
headers = get_headers(config['admin_api_key'])
try:
response = requests.post(url, json=post_data, headers=headers)
response.raise_for_status()
data = response.json()
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# PUT 请求需要带上 ID
url = f"{api_url}/posts/{post_id}/?source=html"
response = requests.put(url, json=update_data, headers=headers)
response.raise_for_status()
data = response.json()
No suspicious patterns detected.