T09 · Insecure Skill Coding Practices
- Location
scripts/publish.py:303- Finding
Markdown image references can cause arbitrary local files to be uploaded
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill matches its Feishu publishing purpose, but it needs review because it can automatically read broad credential files and may upload unintended local files through Markdown image references.
Install only if you trust the Markdown inputs and the workspace where it runs. Prefer explicit environment variables or a dedicated config file, avoid running it in directories with unrelated .env files, review any Markdown image paths before publishing, and use public sharing or automatic owner transfer only for content intended to leave your control.
scripts/publish.py:303Markdown image references can cause arbitrary local files to be uploaded
scripts/publish.py:11Implicit configuration discovery reads overbroad credential files and permits unintended publication settings
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
> - 其他情况,默认按内部 `userid` 工号移交。
>
> ```env
> # 在 .env 中增加如下配置,即可实现发文后全自动过户!
> FEISHU_ADMIN=your_name@company.com
> ```
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
> - 其他情况,默认按内部 `userid` 工号移交。
>
> ```env
> # 在 .env 中增加如下配置,即可实现发文后全自动过户!
> FEISHU_ADMIN=your_name@company.com
> ```
The script automatically loads secrets from multiple .env locations, including a shared agent directory under ~/.openclaw. In an agent/skill context, this broad secret discovery behavior can expose unrelated credentials to the skill and enables credential harvesting from parent/global workspaces without explicit user consent.
print(f"🔑 已加载配置: {file_path}")
# 环境变量加载 (由于 load_env_file 是如果不存则添加,所以最先加载的优先级最高)
# 优先级: 系统环境变量 > ~/.openclaw/.env > ~/.config/feishu-doc-publisher/.env > skill 目录/.env
OPENCLAW_ENV_PATH = os.path.join(str(Path.home()), '.openclaw', '.env')
load_env_file(OPENCLAW_ENV_PATH)
Loading a skill-specific global config directory is less suspicious than reading arbitrary parent paths, but it still causes the script to ingest credentials from disk automatically. In security-sensitive agent environments, implicit secret loading expands the skill's access beyond what is necessary and increases accidental credential exposure risk.
# 环境变量加载 (由于 load_env_file 是如果不存则添加,所以最先加载的优先级最高)
# 优先级: 系统环境变量 > ~/.openclaw/.env > ~/.config/feishu-doc-publisher/.env > skill 目录/.env
OPENCLAW_ENV_PATH = os.path.join(str(Path.home()), '.openclaw', '.env')
load_env_file(OPENCLAW_ENV_PATH)
GLOBAL_CONFIG_DIR = os.path.join(str(Path.home()), '.config', 'feishu-doc-publisher')
The script loads a .env from the skill directory, meaning anyone who can place or modify files in that directory can influence credentials used by the publisher. This can redirect publishing operations to attacker-controlled Feishu applications or accounts and is especially risky when skills are installed from untrusted sources.
load_env_file(OPENCLAW_ENV_PATH)
GLOBAL_CONFIG_DIR = os.path.join(str(Path.home()), '.config', 'feishu-doc-publisher')
GLOBAL_ENV_PATH = os.path.join(GLOBAL_CONFIG_DIR, '.env')
load_env_file(GLOBAL_ENV_PATH)
SKILL_DIR_ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), '.env')
Reading a .env from the parent directory is a classic overbroad secret search pattern. It allows this skill to access secrets belonging to the wider workspace or neighboring projects, which is dangerous in multi-project, shared, or agent-executed environments because it breaks least privilege.
GLOBAL_ENV_PATH = os.path.join(GLOBAL_CONFIG_DIR, '.env')
load_env_file(GLOBAL_ENV_PATH)
SKILL_DIR_ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), '.env')
load_env_file(SKILL_DIR_ENV_PATH)
PARENT_DIR_ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), '.env')
The current working directory may be attacker-influenced in agent executions, so auto-loading .env from os.getcwd() can cause the skill to ingest arbitrary credentials or configuration planted in the run directory. This creates both credential exposure and configuration hijacking risk.
SKILL_DIR_ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), '.env')
load_env_file(SKILL_DIR_ENV_PATH)
PARENT_DIR_ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), '.env')
load_env_file(PARENT_DIR_ENV_PATH)
CURRENT_DIR_ENV_PATH = os.path.join(os.getcwd(), '.env')
This conditional still permits automatic .env loading from the current directory whenever it differs from the other probed paths, so the dangerous behavior remains. In this skill's context, broad implicit secret ingestion is more dangerous because the tool runs with network access to Feishu and can use harvested credentials immediately.
PARENT_DIR_ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), '.env')
load_env_file(PARENT_DIR_ENV_PATH)
CURRENT_DIR_ENV_PATH = os.path.join(os.getcwd(), '.env')
if CURRENT_DIR_ENV_PATH not in [SKILL_DIR_ENV_PATH, PARENT_DIR_ENV_PATH, GLOBAL_ENV_PATH, OPENCLAW_ENV_PATH]:
load_env_file(CURRENT_DIR_ENV_PATH)
This markdown file presents substantive skill-facing release notes entirely in Chinese, with no indication that the language is optional or that the skill is region-specific. Under the language/locale policy rule, forcing a specific language without user opt-in is a natural-language policy concern.
The README explicitly documents a mode that makes generated Feishu documents publicly readable on the internet, but it does not prominently warn users that this can expose sensitive internal content, metadata, or embedded secrets to anyone with the link. In a document-publishing skill, normalizing public sharing without strong cautions increases the likelihood of accidental data disclosure.
The skill requires access to environment variables and the network to publish documents, but it does not declare an explicit tool scope such as permissions or allowed-tools. This weakens sandboxing and reviewability because an agent may invoke the skill without a clear, least-privilege contract describing what external capabilities it will use.
This code reads a local file from disk and transmits its contents to the Feishu media upload API, but there is no confirmation prompt, user-facing log/print, or explanatory comment warning that local file data will be sent externally. Because this is a code file and the operation transmits user/system data over the network, it matches the missing user warning criteria.
The manifest frames the skill as publishing Markdown to Feishu documents, with optional public sharing and ownership transfer mentioned in configuration notes. However, this file implements direct permission reconfiguration and owner transfer operations that materially change access control and document ownership, which goes beyond the core act of publishing content itself.
This function can broaden document sharing to external or anyone-with-link access, and even editable access, based solely on the supplied share_type. In a publishing skill, this can unintentionally expose sensitive document contents outside the tenant if upstream input is wrong, untrusted, or insufficiently confirmed. The skill context makes this more dangerous because the tool is designed to send user-authored content to a collaboration platform where accidental over-sharing has real confidentiality impact.
This function transfers document ownership and triggers notification using only provided member identifiers, with no built-in confirmation or safeguard. If invoked unexpectedly or with manipulated inputs, the original user may lose administrative control over the published document, affecting access management, auditability, and recovery. The risk is elevated because ownership transfer is a high-impact administrative action, even though it is mentioned in the skill description.
The usage guidance says '当用户要求将一个 Markdown 文件发布到飞书时' ('when the user asks to publish a Markdown file to Feishu'), which is an open-ended natural-language trigger rather than a narrowly scoped invocation rule. The file does not provide explicit trigger phrases, constraints, or negative examples to distinguish intended activation from similar everyday requests.
The code emits user-visible exception messages in Chinese, and similar hard-coded Chinese strings appear throughout the file, with no option to choose locale or language. This can violate language/locale policy when a skill forces a specific language without user opt-in.
No suspicious patterns detected.