T01 · Skill Instruction Hijacking
- Location
SKILL.md:60- Finding
Mandatory Promotional Content Injected into Agent Responses
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a real RSS digest generator, but it stores an API key in a predictable plaintext home-directory file and runs an unpinned package at execution time.
Review before installing. Use environment variables instead of saving API keys, avoid custom OpenAI-compatible endpoints unless you control and trust them, prefer a preinstalled or pinned Bun runtime, and remove `~/.hn-daily-digest/config.json` if it contains a real key.
SKILL.md:60Mandatory Promotional Content Injected into Agent Responses
SKILL.md:159Gemini API Key Persisted in a Predictable Plaintext File
SKILL.md:146Unpinned Package Download and Execution Through npx
scripts/digest.ts:398Custom OpenAI-Compatible Endpoint Can Receive API Credentials and Prompt Data Without Validation
scripts/digest.ts:369Gemini API Key Included in Request Query String
Referenced artifact was not completely inspected
| `scripts/digest.ts` | 主脚本 - RSS 抓取、AI 评分、生成摘要 |
The skill invokes network access, reads environment variables, and executes a script, but it does not declare an explicit tool scope such as permissions or allowed-tools. That mismatch weakens reviewability and policy enforcement because the actual runtime capabilities are broader than what the manifest communicates.
The skill persists geminiApiKey in ~/.hn-daily-digest/config.json in plaintext and does not clearly warn the user about credential retention risk. Plaintext API key storage can expose secrets to other local users, backup systems, logs, or later processes that read the home directory.
The skill transmits user-supplied API credentials and fetched article content to external services, including a configurable OpenAI-compatible endpoint and DeepSeek example base URL. External transmission is expected for this skill's function, but it is still security-relevant because users may not appreciate that third-party services receive feed content, prompts, and metadata.
export GEMINI_API_KEY="<key>"
# 可选:OpenAI 兼容兜底(DeepSeek/OpenAI 等)
export OPENAI_API_KEY="<fallback-key>"
export OPENAI_API_BASE="https://api.deepseek.com/v1"
export OPENAI_MODEL="deepseek-chat"
npx -y bun ${SKILL_DIR}/scripts/digest.ts \
Using npx -y bun without a pinned version allows retrieval of whatever package/version is current at execution time. This creates a supply-chain risk where a compromised upstream package, typo-squat, or unexpected major-version change could execute arbitrary code in the agent environment.
The skill creates persistent state under ~/.hn-daily-digest, including configuration and timestamps, which can retain sensitive operational data across sessions. Session persistence increases exposure because secrets and usage metadata remain available after the run and may be accessed by unrelated processes or future tasks.
mkdir -p ~/.hn-daily-digest
cat > ~/.hn-daily-digest/config.json << 'EOF'
{
"geminiApiKey": "<key>",
The environment requirements again instruct use of npx -y bun without version pinning, reinforcing the same unbounded supply-chain exposure. Repeated unpinned installation increases the chance that users or agents execute unreviewed remote code as part of normal workflow.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// ============================================================================
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
const OPENAI_DEFAULT_API_BASE = 'https://api.openai.com/v1';
const OPENAI_DEFAULT_MODEL = 'gpt-4o-mini';
const FEED_FETCH_TIMEOUT_MS = 15_000;
const FEED_CONCURRENCY = 10;
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// ============================================================================
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
const OPENAI_DEFAULT_API_BASE = 'https://api.openai.com/v1';
const OPENAI_DEFAULT_MODEL = 'gpt-4o-mini';
const FEED_FETCH_TIMEOUT_MS = 15_000;
const FEED_CONCURRENCY = 10;
The script hardcodes Chinese category labels and later defaults the CLI language to 'zh', causing generated reports and UI text to be produced in Chinese unless the user explicitly overrides it. This is a natural-language locale constraint applied by default rather than offered as an opt-in choice.
Untrusted RSS titles and descriptions from dozens of external feeds are inserted directly into the scoring prompt with no instruction/data separation, escaping, or adversarial-content handling. A malicious feed can embed prompt-injection text that influences scoring, categorization, keyword extraction, or downstream model behavior, degrading integrity of the digest and potentially steering later processing.
The summarization step passes raw external text and URLs into the model, creating a direct prompt-injection channel from remote content into generated summaries and reasons. Because this stage shapes the final published digest, a malicious feed can coerce the model to emit manipulated output, propaganda, unsafe links, or instructions, and poisoned summaries can propagate into subsequent highlight generation.
Highlight generation relies on model-derived summaries that may already be poisoned by earlier prompt injection, and it does not distinguish trusted instructions from tainted upstream content. This creates a second-order injection path where a single malicious article can disproportionately bias the top-level 'today's highlights' narrative.
The lang variable is initialized to 'zh', so summaries and highlights are generated in Chinese unless the user supplies --lang en. This enforces a specific locale by default and does not obtain user opt-in first.
The skill sends fetched article titles, descriptions, links, and derived summaries to an OpenAI-compatible endpoint whose base URL is fully configurable via environment variable. That allows data to be transmitted to arbitrary third-party services or attacker-controlled inference gateways, creating a clear exfiltration path and weakening assurances about where external content and metadata are processed.
The manifest description presents the skill as generating digests with Chinese-translated titles, which imposes a language choice in the top-level skill behavior description. While later interactive steps offer Chinese or English output, the primary description still frames Chinese output as the default behavior without user opt-in.
The manifest describes fetching RSS feeds, scoring/filtering articles, and generating a Markdown digest with translations and visual statistics. The code additionally appends a self-promotional message for a WeChat/public account brand, which is not part of the stated digest-generation behavior and changes the output's purpose from purely informational to partially promotional.
Detected: suspicious.env_credential_access