Back to skill

Security audit

职业规划 + 简历生成 + 求职优化

Security checks for vulnerabilities and agentic risk

Overview

The skill’s career and resume features are coherent, but its renderer can accidentally include unrelated local files and generated reports can load external code despite offline claims.

Review before installing. Use only trusted resume YAML files, avoid remote avatars and custom theme paths, do not publish generated resumes or reports until you inspect them, and prefer a patched version that restricts avatar files to a local image directory, allowlists themes, vendors Chart.js locally, validates URL schemes, and pins dependencies.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
modules/resume-builder/scripts/render.py:32
Finding

Arbitrary Local File Disclosure Through Unrestricted Avatar Paths

Content
View full analysis
dict: """Resolve avatar path relative to resume.yaml and convert to base64 data URI.""" avatar = (data.get("basics") or {}).get("avatar") if not avatar or avatar.startswith("data:") or avatar.startswith("http"): return data avatar_path = (resume_dir / avatar).resolve() if not avatar_path.is_file(): print(f"⚠️ avatar not found: {avatar_path}", file=sys.stderr) return data mime = mimetypes.guess_type(str(avatar_path))[0] or "image/jpeg" b64 = base64.b64encode(avatar_path.read_bytes()).decode() data["basics"]["avatar"] = f"data:{mime};base64,{b64}" return data ``` The schema accepts any string without path or file-type restrictions: ```json "avatar": {"type": "string", "description": "本地路径或 URL"} ``` ### Technical Analysis The renderer treats the user-controlled `basics.avatar` value as a filesystem path. Although `Path.resolve()` normalizes the path, the resolved result is not checked against an approved base directory. Consequently, both absolute paths and relative traversal sequences such as `../../` can reference any regular file readable by the process. The file contents are read using `read_bytes()`, Base64-encoded, and copied into generated resume output as a data URI. The implementation also does not verify that the selected file is an image. MIME type inference is based only on the filename, and an unrecognized file defaults to `image/jpeg`. This permits arbitrary text or binary files to be embedded. ### Attack Path 1. An attacker supplies or influences a resume YAML file. 2. The attacker sets the avatar field to a sensitive fil ...[truncated 1185 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
modules/resume-builder/scripts/render.py:47
Finding

External Jinja Template Loading Through Theme Path Traversal

Content
View full analysis
str: theme_dir = THEMES_DIR / theme if not (theme_dir / "template.html.j2").exists(): raise SystemExit(f"❌ Theme not found: {theme_dir}") env = Environment( loader=FileSystemLoader(str(theme_dir)), autoescape=select_autoescape(["html", "xml"]), trim_blocks=True, lstrip_blocks=True, ) tmpl = env.get_template("template.html.j2") return tmpl.render(data=data) ``` The theme can originate directly from command-line or resume input: ```python ap.add_argument("--theme", default=None, help="theme name (default: from data.meta.theme or 'classic')") ``` ```python theme = args.theme or (data.get("meta") or {}).get("theme") or "classic" ``` The schema does not restrict it to bundled themes: ```json "theme": {"type": "string", "default": "classic"} ``` ### Technical Analysis The `theme` value is appended to `THEMES_DIR` without an allowlist or canonical containment check. A value containing `../` components can escape the bundled theme directory. A platform-supported absolute path may also replace the base path entirely. If a `template.html.j2` file exists in the selected directory, the application loads it into a normal Jinja `Environment`. Autoescaping protects generated HTML content but does not sandbox template execution. Jinja templates can access object attributes and Python internals unless a sandbox and strict attribute controls are used. This creates a code-execution boundary violation when an attacker can place a template on the local filesystem and then cause an imported resume to select that directory. The issue can a ...[truncated 1716 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
modules/resume-builder/scripts/render.py:32
Finding

Server-Side Request Forgery Through Remote Avatar Rendering

Content
View full analysis
dict: """Resolve avatar path relative to resume.yaml and convert to base64 data URI.""" avatar = (data.get("basics") or {}).get("avatar") if not avatar or avatar.startswith("data:") or avatar.startswith("http"): return data ``` The resulting HTML is passed to WeasyPrint: ```python def to_pdf(html: str, out_path: Path, base_url: Path) -> None: try: from weasyprint import HTML except ImportError as e: raise SystemExit("❌ weasyprint not installed. Run: pip install weasyprint") from e HTML(string=html, base_url=str(base_url)).write_pdf(str(out_path)) ``` Templates render the attacker-controlled avatar as a resource URL: ```jinja2 {% if data.basics.avatar %}
avatar
{% endif %} ``` ### Technical Analysis An avatar beginning with `http` bypasses local embedding and remains an external URL in the rendered document. When PDF generation is enabled, WeasyPrint resolves image resources while producing the PDF. No custom URL fetcher, protocol allowlist, hostname validation, DNS validation, or private-network filtering is configured. A crafted resume can therefore instruct the renderer to request attacker-selected HTTP resources from the network context of the Agent. Targets may include loopback services, private network applications, or link-local infrastructure. The same URL may also be fetched when the generated HTML is opened in a browser, creating an external tracking ...[truncated 1332 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
modules/resume-builder/assets/themes/academic/template.html.j2:29
Finding

Unsafe User-Controlled URL Schemes in Generated Resume Links

Content
View full analysis
{% if data.basics.phone %}{{ data.basics.phone }}{% endif %} {% if data.basics.email %}{{ data.basics.email }}{% endif %} {% if data.basics.location %}{{ data.basics.location }}{% endif %} {% if data.basics.website %}{{ data.basics.website }}{% endif %} {% if data.basics.profiles %}
{% for p in data.basics.profiles %} {{ p.network }}: {{ p.username or p.url }} {% endfor %}
{% endif %} ``` The corresponding schema fields accept arbitrary strings: ```json "website": {"type": "string"}, ``` ```json "profiles": { "type": "array", "items": { "type": "object", "required": ["network", "url"], "properties": { "network": {"type": "string"}, "username": {"type": "string"}, "url": {"type": "string"} } } } ``` ### Technical Analysis Jinja autoescaping protects the HTML attribute syntax from quote-based markup injection, but it does not determine whether the URL scheme is safe. Arbitrary strings are accepted as `website` and profile URLs and inserted into `href` attributes. A value such as `javascript:...` can therefore remain an active script-bearing link in generated HTML. Other application-launching or locally sensitive schemes may also be accepted depending on browser and PDF-viewer policy. The vulnerability requires a recipient to activate the crafted link; it is not automatically executed by HTML generation alone. ### Attack Path 1. An attacker supplies resume content containi ...[truncated 1084 chars]
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Warning
Location
modules/career-planner/scripts/render_plan_visual.py:73
Finding

Generated Career Reports Execute Remotely Hosted JavaScript

Content
View full analysis
``` The project documentation states: ```text 全离线,不依赖外部 API。模块间通过文件解耦,可单独使用。 ``` This states that the project is fully offline and does not depend on external APIs, but opening the generated career report retrieves JavaScript from a third-party CDN. ### Technical Analysis Every generated career-plan HTML document references Chart.js from `cdn.jsdelivr.net`. When the report is opened with network access, the browser downloads and executes code supplied by that external service. Although the package version is specified, the document does not provide a Subresource Integrity hash. The effective code executed by the report is therefore not contained in the reviewed Skill package and is not cryptographically bound to known content. This contradicts the project's offline claim and creates a post-review payload channel controlled by third-party infrastructure. ### Attack Path 1. The Agent runs `render_plan_visual.py`. 2. The script creates an HTML report containing the external `
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:73
Finding

Unpinned Python Dependencies Create a Mutable Installation Supply Chain

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (81)

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

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

md
| Trae | 克隆到 `~/.trae/skills/career-toolkit` |
| Cursor | 克隆到 `~/.cursor/skills/career-toolkit`,或在 `.cursor/rules/` 中引用 |
| Windsurf | 克隆到 `~/.windsurf/skills/career-toolkit` |
| Claude Code | 将仓库路径加入项目 `AGENTS.md` 或 `~/.claude/settings.json` 的 skills 列表 |
| Codex (OpenAI) | 在 `codex.yaml` 中注册为 tool,或放入 `~/.codex/skills/` |
| OpenClaw | 在 `.openclaw/config.yaml` 的 `skills` 字段添加本地路径或远程 URL |
| Hermes | 在 `hermes.config.json` 的 `plugins` 中添加仓库路径 |

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The supplied code aligns only with the 'career planning' portion of the description, specifically visualizing Holland/RIASEC results and milestones into HTML. Its primary behavior is report rendering from YAML to HTML. The declared description, however, presents a broader multifunction skill centered on career planning plus resume creation and job-search optimization features. Those additional capabilities are not present in this code chunk. While partial overlap exists, the description materially overstates what this code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

The code does align with one part of the declared description: Holland assessment scoring for career planning. However, the declared purpose presents a much broader multi-function skill covering resume generation, PDF export, JD matching, ATS checks, and quantified rewrite features. None of those capabilities appear in this code chunk. The actual code only processes assessment responses and emits scoring results plus path hints; it does not render resumes, export files to PDF, analyze job descriptions, or optimize resume bullets. Because the described skill materially overstates what this specific code chunk does, this chunk does not accurately represent the full declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk’s primary function is to score a simplified MBTI questionnaire from a YAML file and output MBTI-type results plus career hints. The declared description emphasizes career planning tied to Holland assessment and multiple resume/job-optimization features. While MBTI-based career hints are adjacent to career planning, MBTI is materially different from Holland assessment, and the concrete behavior here is assessment scoring rather than any of the declared resume/JD/ATS/PDF capabilities. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

代码行为与描述仅部分重合。它确实支持简历渲染、主题选择、PDF 导出,以及额外的 JSON/Markdown 导出;但描述中的核心能力还包括职业规划、Holland 测评、行动规划、JD 匹配、ATS 检查、量化改写等,这些在该代码中完全没有体现。该代码的主要目的更窄,实际上是一个本地 resume.yaml -> HTML/PDF/JSON/Markdown 的渲染器,而不是完整的职业规划与求职优化技能。因此应判定为描述与行为存在明显不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

该代码块的实际用途是“将结构化 YAML 简历转换为 Markdown 文档”。这与声明中的大部分核心能力明显不符。声明强调的是综合职业规划与求职优化工具,而代码只覆盖了简历生成链路中的一个很窄的子功能:格式化渲染简历内容。即使把它视为‘简历生成’的一部分,仍然缺失声明中关键的 PDF 导出、多主题渲染、JD/ATS 分析和内容改写等功能。因此这是实质性描述不符,而不是正常的底层实现细节差异。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code chunk does not implement the user-facing capabilities claimed in the description. Its sole evident purpose is validating a resume.yaml file against a schema using jsonschema. While schema validation could be a supporting internal utility for a resume system, the declared purpose focuses on career planning, resume generation/rendering, PDF export, JD matching, ATS checks, and optimization features, none of which appear in this code. Because the actual code’s primary behavior is materially different and undeclared, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · modules/resume-builder/assets/site/index.html (reported line 406)May include surrounding context.

html
</head>
<body>

<!-- Hero -->
<section class="hero">
  <div class="hero-content">
    <div class="hero-badge">Skill</div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · modules/resume-builder/assets/site/index.html (reported line 406)May include surrounding context.

html
</head>
<body>

<!-- Hero -->
<section class="hero">
  <div class="hero-content">
    <div class="hero-badge">Skill</div>

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill tagline is written as an instruction/value proposition entirely in Chinese, and the installation example later also assumes Chinese input. For a general-purpose skill README, this effectively imposes a specific language without documenting that the skill is Chinese-only or offering multilingual use, which matches the locale/language policy concern.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises and documents file-reading/writing behaviors and executable script paths, but the manifest shown does not declare any explicit tool scope such as allowed tools or permissions. That creates an authorization-boundary problem: a host may grant broader capabilities implicitly, and users are not given a clear least-privilege contract for local file access.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger phrases are broad and conversational, increasing the chance the skill activates on ordinary discussion rather than an explicit request. In a skill that can create files, transform personal career data, and route across modules, accidental invocation can lead to unintended processing of sensitive user information or unwanted file generation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest description and trigger vocabulary are Chinese-only, which can amount to a language policy constraint if the skill requires that locale without user opt-in. The file does not state that the skill is China-specific or offer alternative language support.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The routing rules use ambiguous phrases like resume help, career planning, and optimization without strong disambiguation or confirmation. Because the skill chains into modules that may read/write files and process resumes or job descriptions, ambiguous routing can cause unintended handling of personal data and actions beyond the user's intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The triggers mention sharing resumes to Feishu, mentors, or HR without any privacy or transmission warning. Since resumes routinely contain phone numbers, emails, education, employment history, and other personal data, invoking sharing-related behavior without clear disclosure can lead to accidental external dissemination of sensitive information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documented cross-module automation automatically maps profile data into a new resume file without explicit notice or consent at the transfer point. Because career profiles and resumes contain personal and potentially sensitive data, silent propagation between files/modules increases privacy risk and the chance of unintended data retention or disclosure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The module's natural-language instructions, example user utterances, and outputs are all presented in Chinese, with no indication that other languages are supported or that Chinese is required for a region-specific reason. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest explicitly advertises 'JD 关键词匹配、ATS 检查、Bullet 量化改写' as part of the skill’s purpose. However, this module documentation states those functions are not covered here and are routed to a separate resume-optimizer module later, which diverges from the behavior users would expect from the manifest description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module instructs the agent to create local files containing sensitive career-profile data without explicitly warning the user that their personal information will be stored on disk. Because this data can include education, goals, assessments, and potentially identifying information, silent persistence increases privacy and retention risk if the workspace is shared, synced, or later exposed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module recommends publishing a career-planning report to Feishu without explicitly warning that user career data will be transmitted to an external third-party service. This is dangerous because the report may contain personal profile details, assessments, and plans that the user may not expect to leave the local environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The HTML visualization workflow instructs publication to Feishu without disclosing that generated report content, including RIASEC scores and milestone timelines, will be externally transmitted. Visual reports often consolidate sensitive information, so undisclosed sharing can create a meaningful privacy and confidentiality risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This YAML assessment content uses Chinese throughout, including item text, descriptions, and career hints, with no indication that the skill is China-specific or that users can opt into another language. That can violate language/locale policy when a skill implicitly forces one language on all users without documented justification or choice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document explicitly instructs the agent to persist sensitive personal and career-profile data to profile.yaml across sessions, but it provides no requirement to obtain informed user consent, disclose retention, or minimize what is stored. In this skill context, the data includes identity, education, family preference, economic constraints, health status, GPA, and other potentially sensitive information, so silent persistence increases privacy and misuse risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The entire playbook, including headings and output instructions, is written exclusively in Chinese and instructs the agent to produce a deliverable without any indication that the user can choose another language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The playbook hard-codes a mainland China campus recruiting timeline and labels it as the default flow without any user choice, locale detection, or disclaimer. This can mislead users outside that region or users with different graduation cycles, causing materially wrong job-search timing and planning outputs.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.