Back to skill

Security audit

Candidate Assessment

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it automatically installs an unpinned third-party package and stores sensitive hiring materials without clear retention guidance.

Review before installing. Use it only on resumes and job descriptions you are authorized to process, run it in a contained environment, avoid PDF/DOCX input unless pdfmuse has been installed from a vetted pinned version, and delete intermediate resume/JD extracts and generated assessments when no longer needed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (1)

T08 · Insecure Dependencies

Warning
Location
scripts/read_jd.py:22
Finding

Automatic Installation of an Unpinned Third-Party Dependency

Content
View full analysis

Vulnerability Details

File Location: scripts/read_jd.py, lines 22–32
Vulnerability Type: Supply-chain risk caused by automatic installation of an unpinned dependency
Risk Level: Medium

Vulnerable Code

python
def _ensure_pdfmuse():
    try:
        import pdfmuse  # noqa: F401
        return pdfmuse
    except ImportError:
        print("pdfmuse not found -- installing (one-time)...", file=sys.stderr)
        subprocess.run([sys.executable, "-m", "pip", "install", "-q", "pdfmuse"],
                       check=True)
        import pdfmuse  # noqa: F401
        return pdfmuse

The dependency manifest also leaves the package unpinned:

text
pdfmuse

This occurs at requirements.txt, line 1.

Technical Analysis

When a PDF or DOCX job description is processed and pdfmuse is unavailable, the script automatically invokes pip to retrieve and install the latest package selected by the configured Python package index. Neither the runtime installation command nor requirements.txt specifies an exact version or verifies an integrity hash.

As a result, the code ultimately executed can change after the Skill has been reviewed. A compromised upstream release, compromised package index, malicious index configuration, or dependency-resolution attack could introduce attacker-controlled installation or import-time code.

The subprocess invocation uses an argument list and does not expose a shell-injection flaw. The security issue is the implicit acquisition and execution of mutable third-party code.

Attack Path

  1. An attacker compromises a future pdfmuse release or influences the package source used by the environment.
  2. The user invokes scripts/read_jd.py with a PDF or DOCX file on a system where pdfmuse is not installed.
  3. read_jd() calls _ensure_pdfmuse().
  4. _ensure_pdfmuse() runs:
    bash
    python -m pip install -q pdfmuse
    
  5. `pip ...[truncated 820 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove automatic package installation from normal document-processing execution.
  2. Require dependencies to be installed through an explicit, user-approved setup step.
  3. Pin pdfmuse to a reviewed exact version instead of using an unconstrained package name.
  4. Use a lock file or hash-verified requirements file, for example:
    text
    pdfmuse==REVIEWED_VERSION --hash=sha256:REVIEWED_DISTRIBUTION_HASH
    
  5. Install dependencies in a dedicated virtual environment with least-privilege permissions.
  6. Configure an approved package index and disable untrusted supplemental indexes.
  7. Fail safely with installation instructions when the dependency is missing rather than modifying the environment automatically.
  8. Add dependency-update review and vulnerability scanning to the release process.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill presents itself as a candidate assessment workflow, but the documented behavior includes rendering HTML and optionally producing a PDF via headless Chrome/Chromium/Edge execution, which is a materially different capability than pure text scoring. Hidden or under-emphasized execution of browser automation expands the execution surface and may process untrusted generated content or local files in a browser context without clear disclosure or consent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README presents the report as a Chinese-titled output (《候选人内部评估报告》) and provides only Chinese invocation examples, without stating that language is configurable or optional. This can constitute a language/locale policy violation because it implies a fixed language choice without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README explicitly encourages processing resumes and job descriptions, which commonly contain sensitive personal data such as names, contact details, work history, education, and sometimes compensation or immigration information, but it provides no privacy, minimization, retention, or consent guidance. In a hiring workflow, this omission can lead users to process regulated or confidential applicant data without safeguards, increasing the risk of unauthorized exposure, over-collection, or noncompliant handling.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README says the skill can be triggered by natural-language phrases like "用这份 JD 评估这个候选人" and "简历 JD 匹配评估", but it does not define the exact trigger set, boundaries, or when the skill should not activate. These phrases are broad enough to overlap with ordinary recruiting conversation, increasing the risk of unintended invocation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly instructs the agent to invoke shell commands, read local files in multiple formats, write output artifacts, and open the generated report in a browser, yet it declares no tool restrictions such as allowed-tools or permissions. That creates unnecessary ambient authority: if the skill is triggered in a broad recruiting context, the agent may gain filesystem and shell access beyond what is minimally required, increasing the blast radius of prompt misuse or path manipulation in downstream steps.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The description says to use the skill whenever the user wants to assess, score, match, or generate a candidate evaluation report, but it does not define narrower trigger constraints or exclusion conditions. This broad phrasing increases the chance of unintended invocation for general hiring or resume-help conversations rather than explicit resume-to-JD assessment tasks.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The workflow persists sensitive recruitment artifacts to disk: parsed resume data, extracted markdown, JD text, assessment.json, report.html, and optionally PDF output. Resumes and hiring assessments commonly contain PII and subjective evaluation notes, so writing them to session or workspace storage without retention controls can expose personal data to later sessions, shared environments, backups, or unintended users.

Content

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

  • 1. Parse the resume (resume-parsing skill) → resume.json + .extract.md
  • 2. Read the JD (read_jd.py) → jd text
  • 3. Read reference/assessment-prompt.md
  • 4. Evaluate → write assessment.json (per the schema there)
  • 5. Render → render_report.py assessment.json --out report.html
  • 6. Open report.html in the browser
text

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file specifies a Chinese-labeled export button and describes the report as a Chinese internal evaluation report, but it does not state that language choice is optional or based on user preference. This can violate language/locale policy by implicitly forcing a specific language experience without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document explicitly requires Chinese full-width punctuation and states that Chinese values should be preserved in the JSON output, which imposes a specific language/locale convention. This is a natural-language policy concern because the skill does not offer the user any language or locale choice or explain a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Auto-installing a Python package during normal execution is unsafe in this skill context because reading a JD should not require package management or fetching code from external sources at runtime. In an agent environment, this expands the trust boundary, adds nondeterministic behavior, and can be abused through dependency confusion, malicious package updates, or execution in privileged environments.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The code invokes pip at runtime to install a package when an import fails. This introduces network access and dynamic code acquisition into a local file-reading utility, creating supply-chain risk and allowing unreviewed code execution if the package source, dependency chain, or installation environment is compromised.

Content

Scanner excerpt · scripts/read_jd.py (reported line 29)May include surrounding context.

python
return pdfmuse
    except ImportError:
        print("pdfmuse not found -- installing (one-time)...", file=sys.stderr)
        subprocess.run([sys.executable, "-m", "pip", "install", "-q", "pdfmuse"],
                       check=True)
        import pdfmuse  # noqa: F401
        return pdfmuse

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code emits HTML with lang="zh-CN" and Chinese-only UI strings such as the title and export button text, which forces a specific language/locale in the skill output. The file does not provide a language option or indicate that the tool is intentionally limited to a China-specific workflow, so this is a natural-language policy concern.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_report.py (reported line 376)May include surrounding context.

python
base = ["--headless=new", "--disable-gpu", f"--print-to-pdf={pdf_path}", url]
    # --no-pdf-header-footer strips the browser's date/URL chrome (Chrome 111+).
    try:
        subprocess.run([chrome, "--no-pdf-header-footer", *base], check=True,
                       timeout=90, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    except subprocess.CalledProcessError:
        subprocess.run([chrome, *base], check=True, timeout=90,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_report.py (reported line 379)May include surrounding context.

python
subprocess.run([chrome, "--no-pdf-header-footer", *base], check=True,
                       timeout=90, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    except subprocess.CalledProcessError:
        subprocess.run([chrome, *base], check=True, timeout=90,
                       stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    if not os.path.exists(pdf_path):
        raise SystemExit("Headless Chrome did not produce a PDF.")

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency is specified without a version pin, so installs may pull in different releases over time, including a newly introduced vulnerable or malicious version. In this skill, the package is used for document/PDF handling, which increases risk because parsing complex file formats from user-supplied inputs expands the attack surface and makes supply-chain drift more dangerous.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
pdfmuse

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The top-level docstring states 'Supports .txt / .md / .markdown / .rtf directly', while PLAIN_EXT excludes .rtf and the code handles .rtf through a separate _strip_rtf branch. This is not just incomplete documentation: it inaccurately describes RTF as part of the direct/plain-text path when the implementation uses distinct conversion logic.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.