T09 · Insecure Skill Coding Practices
- Location
scripts/setup.py:103- Finding
Notion API Key Stored Without Restrictive File Permissions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill appears purpose-aligned for a Notion-based music recommendation workflow, but it needs review because it handles a Notion API key and can write/send data without strong credential-safety guidance.
Review this before installing if your Notion integration can access sensitive pages. Prefer a narrowly scoped Notion integration, avoid passing the key on the command line, check that ~/.config/music-weekly/config.json is only readable by you, and confirm the delivery target before allowing the workflow to send messages or media.
scripts/setup.py:103Notion API Key Stored Without Restrictive File Permissions
SKILL.md:51Notion API Key Accepted and Documented as a Command-Line Argument
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
body = json.dumps(data).encode() if data else None
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
try:
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except urllib.error.HTTPError as e:
err = e.read().decode()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
body = json.dumps(data).encode() if data else None
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
try:
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except urllib.error.HTTPError as e:
err = e.read().decode()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
body = json.dumps(data).encode() if data else None
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
try:
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except urllib.error.HTTPError as e:
err = e.read().decode()
The manifest says the skill should activate for broadly defined first-time setup requests, which can cause the agent to invoke it in situations where the user did not specifically request this workflow. Because the skill performs configuration and setup tasks, broad triggering increases the chance of unintended side effects and secret handling without sufficiently explicit user intent.
The installation step uses npx clawhub install music-weekly without pinning a specific package version or integrity reference. That creates a supply-chain risk: a later compromised or malicious release of the package/tool could be fetched and executed in the user's environment during setup.
The skill advertises a one-command setup that automatically creates config files, directories, history logs, and a Notion database, but it does not present a prominent up-front warning or confirmation requirement for those side effects. In an agent context, this can lead to silent modification of the user's filesystem and external services, which is risky even if the actions are intended.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
- **QQ Bot:** 图片需要先复制到配置的 `media_dir` 目录,使用 `<qqmedia>` 标签
- **其他频道:** 使用 `message` 工具的 `media` 参数传本地文件
- 文件权限问题:确保图片文件可读(`chmod 644`)
---
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: Notion API key not configured.")
print(f"Set NOTION_KEY env var or write config to {CONFIG_PATH}")
return None
url = f"https://api.notion.com/v1{path}"
body = json.dumps(data).encode() if data else None
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
try:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: Notion API key not configured.")
print(f"Set NOTION_KEY env var or write config to {CONFIG_PATH}")
return None
url = f"https://api.notion.com/v1{path}"
body = json.dumps(data).encode() if data else None
req = urllib.request.Request(url, data=body, headers=HEADERS, method=method)
try:
This code hardcodes Chinese user-facing text such as the sender name and, throughout the script, Chinese prompts and status messages. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation because users are not offered a locale or language choice.
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.
help="Delivery channel (qqbot/telegram/discord/signal/wecom/feishu)")
parser.add_argument("--target", help="Delivery target ID for the channel")
parser.add_argument("--auto", action="store_true",
help="Auto mode: skip prompts, use defaults if not specified")
args = parser.parse_args()
The string literal "🎵 音乐编辑" sets a specific language for user-facing output in the configuration. Because this file provides no opt-in, language selection mechanism, or documented regional justification, it may violate the language/locale policy requirement.
In this markdown workflow, the instructions explicitly download album artwork from a remote URL to a local path, which performs both network access and a file write. The document also later appends entries to a history log, but it does not include any warning that running the workflow will modify local files or fetch external content.
The markdown instructs sending messages and media to Telegram, Discord, Signal, or QQ Bot using configured delivery targets, which transmits collected content to third-party services. There is no accompanying warning that album selections, links, media, and channel target details will be sent externally.
No suspicious patterns detected.