T01 · Skill Instruction Hijacking
- Location
scripts/feishu_helper.py:184- Finding
Persistent Promotional Link Injection into Generated Meeting Content
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This meeting automation skill has legitimate features, but it also contains unrelated review instructions, hidden promotional links, and under-scoped network behavior that needs manual review before use.
Review carefully before installing. Use only with non-sensitive meetings and test credentials unless the maintainer removes the unrelated GitHub/repository instructions and hardcoded promotional links, validates all outbound URLs, enforces download size limits, and makes cloud transcription an explicit validated choice.
scripts/feishu_helper.py:184Persistent Promotional Link Injection into Generated Meeting Content
SKILL.md:107Unrelated Repository-Modification and External Review Instructions Embedded in the Skill
scripts/meeting_fetcher.py:44Arbitrary URL Download Enables SSRF and Unbounded Disk Consumption
scripts/meeting_fetcher.py:174WeCom Access Token May Be Disclosed to an Unvalidated Download Host
scripts/main_processor.py:13Meeting Content Can Be Posted to Arbitrary Webhook Destinations
scripts/transcribe.py:184Invalid Privacy-Mode Values Silently Cause Cloud Audio Upload
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
)
# 向飞书服务器请求令牌
response = requests.post(
f"{BASE_URL}/auth/v3/tenant_access_token/internal",
json={"app_id": FEISHU_APP_ID, "app_secret": FEISHU_APP_SECRET},
timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
# 发送请求
response = requests.post(
f"{BASE_URL}/im/v1/messages",
headers=get_auth_headers(),
params={"receive_id_type": "chat_id"},
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
# 发送请求
response = requests.post(
f"{BASE_URL}/im/v1/messages",
headers=get_auth_headers(),
params={"receive_id_type": "chat_id"},
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if due_ms:
payload["due"] = {"timestamp": str(due_ms // 1000)}
response = requests.post(
f"{BASE_URL}/task/v2/tasks",
headers=get_auth_headers(),
json=payload,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/bitable/v1/apps/{atoken}/tables/{tbl}/records/batch_create"
payload = {"records": [{"fields": r} for r in records]}
response = requests.post(
url,
headers=get_auth_headers(),
json=payload,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not WECOM_CORP_ID or not WECOM_AGENT_SECRET:
raise ValueError("❌ 缺少 WECOM_CORP_ID 或 WECOM_AGENT_SECRET")
r = requests.get(
"https://qyapi.weixin.qq.com/cgi-bin/gettoken",
params={"corpid": WECOM_CORP_ID, "corpsecret": WECOM_AGENT_SECRET},
timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not FEISHU_APP_ID or not FEISHU_APP_SECRET:
raise ValueError("❌ 缺少 FEISHU_APP_ID 或 FEISHU_APP_SECRET")
r = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": FEISHU_APP_ID, "app_secret": FEISHU_APP_SECRET},
timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return True
try:
response = requests.post(
f"{BILLING_URL}/charge",
headers={
"X-API-Key": SKILLPAY_API_KEY,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return -1
try:
response = requests.get(
f"{BILLING_URL}/balance",
headers={"X-API-Key": SKILLPAY_API_KEY},
params={
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return "https://skillpay.me"
try:
response = requests.post(
f"{BILLING_URL}/payment-link",
headers={
"X-API-Key": SKILLPAY_API_KEY,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"❌ 缺少配置:请设置 WECOM_CORP_ID 和 WECOM_AGENT_SECRET"
)
response = requests.get(
f"{BASE_URL}/gettoken",
params={"corpid": WECOM_CORP_ID, "corpsecret": WECOM_AGENT_SECRET},
timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"text": {"content": content},
}
response = requests.post(
f"{BASE_URL}/message/send",
params={"access_token": get_access_token()},
json=payload,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"text": {"content": content},
}
response = requests.post(
f"{BASE_URL}/message/send",
params={"access_token": get_access_token()},
json=payload,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"text": {"content": content},
}
response = requests.post(
f"{BASE_URL}/message/send",
params={"access_token": get_access_token()},
json=payload,
The webhook destination is taken directly from an environment variable and used as the full POST target without validation or domain restriction. If that variable is misconfigured or attacker-controlled, sensitive message content can be silently exfiltrated to an arbitrary endpoint instead of WeCom.
},
}
response = requests.post(WECOM_WEBHOOK_URL, json=payload, timeout=10)
response.raise_for_status()
result = response.json()
This markdown webhook function has the same issue as the text webhook path: it trusts an environment-provided full URL as the outbound destination. In environments where configuration can be influenced, this creates an easy exfiltration primitive for arbitrary markdown content.
payload = {"msgtype": "markdown", "markdown": {"content": content}}
response = requests.post(WECOM_WEBHOOK_URL, json=payload, timeout=10)
response.raise_for_status()
result = response.json()
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
.env
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import requests
from dotenv import load_dotenv
# 读取 .env 文件里的配置(只读取,不联网)
load_dotenv()
# 从环境变量读取配置(这里只是读取变量,不会发起任何网络请求)
No suspicious patterns detected.