Back to skill

Security audit

Career News

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent local career-news prompt generator, but it stores unvalidated profile text that can later be reused in agent prompts and executable command hints.

Install only if you are comfortable with a local CLI skill that stores user news preferences and can be scheduled with cron. Avoid putting untrusted text, shell characters, or multiline instructions in region or keyword fields, and review generated prompts or commands before letting an agent run them automatically.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/morning-push.js:120
Finding

Stored Prompt Injection Through Unvalidated User Profile Fields

Content
View full analysis
k.trim()).filter(Boolean) : []; const fp = path.join(USERS_DIR, `${userId}.json`); const existing = fs.existsSync(fp) ? JSON.parse(fs.readFileSync(fp, 'utf8')) : {}; ``` The persisted values are subsequently inserted directly into agent-facing morning-push instructions: ```js return `[Career News Morning Push | user: ${user.userId} | profession: ${profession}${tag} | lang: en | region: ${region} | ${dateStr}] Please search and compile a morning news brief for this user. Profession: ${cfg.label} Search keywords: ${cfg.keywords.join(', ')}${extraKeywords ? ', ' + extraKeywords : ''} Priority sources: ${cfg.sources.join(', ')} Region focus: ${region.toUpperCase()} ``` The instant-query prompt contains the same unsafe interpolation pattern: ```js console.log(`[Career News Query | profession: ${profession} | lang: en | region: ${region.toUpperCase()} | ${dateStr}] Please find the latest news for a ${cfg.label} professional right now. Keywords: ${allKw.join(', ')} Priority sources: ${cfg.src.join(', ')} Region: ${region.toUpperCase()} ``` The profession-suggestion prompt also embeds stored region data: ```js console.log(`[Career News — Profession Suggestion | user: ${user.userId}] This user's current profession subscriptions: ${allProfs.join(', ')} Primary profession: ${user.profession} Region: ${user.region || 'cn'} Available professions to add: ${available.join(', ...[truncated 2428 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/news-query.js:98
Finding

Shell Command Injection in Generated News Query Commands

Content
View full analysis
k.trim()) : (u.keywords || []); ``` Those values are concatenated into a command presented for execution: ```js if (userLang === 'en') { console.log(`[Career News Query | user: ${u.userId} | profession: ${profLabel} | lang: en | region: ${userRegion.toUpperCase()} | ${ds}]\n→ Run: node scripts/news-query.js ${prof} --lang en --region ${userRegion}${userKw.length ? ' --keywords "' + userKw.join(',') + '"' : ''}`); } else { console.log(`[职业新闻即时查询 | 用户:${u.userId} | 职业:${profLabel} | 语言:zh | 地区:${userRegion.toUpperCase()} | ${ds}]\n→ 执行:node scripts/news-query.js ${prof} --region ${userRegion}${userKw.length ? ' --keywords "' + userKw.join(',') + '"' : ''}`); } ``` ### Technical Analysis The generated command uses string concatenation instead of an argument array or a shell-escaping routine. In particular: - `userRegion` is inserted as an unquoted shell token. - `userKw` is enclosed in double quotes, but embedded double quotes are not escaped. - Shell metacharacters, command substitutions, separators, and line breaks are not rejected. - Values can originate from persistent user profiles. A crafted keyword can close the double-quoted argument and append a second command. A crafted region can inject shell syntax directly because it is not quoted at all. The script only prints the command and does not itself call `exec`, `spawn`, or another command-execution function. Exploitation therefore requires a user, automation component, or AI agent to execute th ...[truncated 1729 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (17)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 58)May include surrounding context.

md
| `scripts/morning-push.js` | Daily 7:00 AM push — generates one brief per profession per user |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 86)May include surrounding context.

md
| `scripts/morning-push.js` | Daily 7:00 AM push — generates one brief per profession per user |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 87)May include surrounding context.

md
| `scripts/morning-push.js` | Daily 7:00 AM push — generates one brief per profession per user |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 88)May include surrounding context.

md
| `scripts/morning-push.js` | Daily 7:00 AM push — generates one brief per profession per user |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 98)May include surrounding context.

md
| `scripts/morning-push.js` | Daily 7:00 AM push — generates one brief per profession per user |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 59)May include surrounding context.

md
| `scripts/news-query.js` | Instant query for any profession (or all of a user's subscriptions) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 80)May include surrounding context.

md
| `scripts/news-query.js` | Instant query for any profession (or all of a user's subscriptions) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 81)May include surrounding context.

md
| `scripts/news-query.js` | Instant query for any profession (or all of a user's subscriptions) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 82)May include surrounding context.

md
| `scripts/news-query.js` | Instant query for any profession (or all of a user's subscriptions) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 83)May include surrounding context.

md
| `scripts/news-query.js` | Instant query for any profession (or all of a user's subscriptions) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

md
| `scripts/register.js` | Register / view / list users |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 68)May include surrounding context.

md
| `scripts/register.js` | Register / view / list users |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 69)May include surrounding context.

md
| `scripts/register.js` | Register / view / list users |

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code sets const lang = user.language || 'zh';, which means users with no stored language preference automatically receive Chinese-language prompts. This is a natural-language policy concern because it forces a locale choice rather than asking the user or using an explicitly documented opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

In --userId mode, the script reads and reveals a user's stored subscription profile based only on a supplied identifier, with no authentication, authorization, or consent check. Because it prints the user's professions, language, region, keywords, and userId-derived context, anyone able to run the script can enumerate or access another user's preferences, creating a privacy and data exposure issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code sets lang to 'zh' by default and only uses English when --lang en is provided. This imposes a specific language without user opt-in, which is a natural-language policy concern unless the locale restriction is explicitly justified or the user is first offered a choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The registration flow defaults --lang to zh and coerces any non-en value back to zh, which imposes a specific language choice unless the user explicitly overrides it. This is a natural-language locale policy concern because the skill does not offer a neutral default or require affirmative user selection.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.