Back to skill

Security audit

Jd Truth Detector

Security checks for vulnerabilities and agentic risk

Overview

This looks like a real job-description analyzer, but its URL scraping is too broad and can send fetched or resume content to a configured LLM service.

Review before installing. Use pasted JD text instead of --jd-url for untrusted links, avoid running URL scraping in environments with access to internal services, prefer a local LLM endpoint for sensitive resumes, and treat generated reports as advisory because job postings can influence the LLM output.

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

Error
Location
scripts/input_parser.py:54
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery and Indirect Data Disclosure

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/analyzer.py:8
Finding

Untrusted Job Description Content Is Embedded Directly into LLM Instructions

Content
View full analysis
list[dict]: msgs = [{"role": "user", "content": _JARGON_PROMPT.format(jd_text=jd_text, stats=str(stats))}] result = llm.chat(msgs) return result if isinstance(result, list) else [] def analyze_culture(jd_text: str, stats: dict, llm) -> dict: red_flags = {k: v for k, v in stats["red_flag_keywords"].items() if v > 0} msgs = [{"role": "user", "content": _CULTURE_PROMPT.format( jd_text=jd_text, red_flags=str(red_flags), structure=str(stats["structure"]) )}] result = llm.chat(msgs) return result if isinstance(result, dict) else {} def analyze_resume_match(jd_text: str, resume_text: str, llm) -> dict | None: if not resume_text or len(resume_text.strip()) < 50: return None msgs = [{"role": "user", "content": _RESUME_PROMPT.format(jd_text=jd_text, resume_text=resume_text)}] result = llm.chat(msgs) return result if isinstance(result, dict) else None ``` The same pattern is also used by `analyze_negotiation()` at `scripts/analyzer.py:96-100`. ### Technical Analysis Job descriptions may originate from attacker-controlled remote pages, local files, or pasted text. The implementation inserts this untrusted content directly into an instruction-bearing prompt without a stro ...[truncated 1996 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (29)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises behaviors that require environment access, file I/O, and network use, but it does not declare any explicit tool scope or permissions boundary. That makes the skill harder to review and increases the chance an agent runtime will grant broader capabilities than users expect, especially since it can read resumes, access config files, and send data to external LLM endpoints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger list contains broad phrases like job description analysis terms that can match ordinary conversation and invoke the skill unexpectedly. In a skill that processes sensitive resumes and may scrape URLs or transmit content to external APIs, accidental activation can cause unintended data handling or user confusion about what is being sent where.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Or ~/.config/jd-truth-detector/config.yaml:

yaml
base_url: https://api.deepseek.com/v1
api_key: sk-...
model: deepseek-chat

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The privacy note says data is sent only to the configured LLM endpoint, but it does not clearly warn users that this may be a third-party hosted API and that pasted resumes and job descriptions will leave the local environment. Because resumes often contain highly sensitive personal and employment information, insufficient disclosure creates a real privacy and compliance risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · config.example.yaml (reported line 1)May include surrounding context.

yaml
base_url: https://api.openai.com/v1
api_key: sk-...
model: gpt-4o-mini

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code sends full resume text to an LLM for analysis without any visible consent, disclosure, minimization, or provider-boundary controls in this file. Resumes commonly contain sensitive personal data such as contact details, employment history, and education, so transmitting them to a third-party or local model backend can create privacy, compliance, and unintended retention risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function accepts a user-provided URL and performs an HTTP request, which causes network transmission and may disclose the user's target resource and related system metadata such as the user agent. Although errors are surfaced, there is no confirmation prompt, user-facing warning, or explanatory comment/docstring that clearly discloses this network behavior as a safety-relevant action.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code sends the provided messages payload to a remote OpenAI-compatible endpoint via chat.completions.create. While the file has a module docstring, it does not include any user-facing warning, log message, confirmation, or inline disclosure that user or system data may be transmitted over the network.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module docstring and function docstring are written entirely in Chinese, including the returned-field description, which indicates a language-specific design with no visible user opt-in or locale-selection mechanism. Under the policy, forcing a specific language without user choice is a natural-language policy concern unless the locale constraint is explicitly justified.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with only a lower bound, so builds may resolve to different versions over time and can silently pick up vulnerable or breaking releases. In a skill that processes external content and calls remote services, lack of deterministic dependency versions increases supply-chain and maintenance risk.

Content

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

text
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

PyYAML is unpinned, which makes the installed version non-deterministic and complicates assurance that a safe release is used. This matters more here because the skill may ingest user-controlled files and content, and YAML libraries have a history of unsafe parsing issues when older versions or insecure loaders are used.

Content

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

text
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0

Unverifiable Dependency: pyyaml has 8 known advisory(ies) (CVE-2019-20477 (Deserialization of Untrusted Data in PyYAML); CVE-2020-1747 (Improper Input Validation in PyYAML); CVE-2020-14343 (Improper Input Validation in PyYAML) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
96% confidence
Finding

PyYAML has known advisories, and because the manifest does not pin a version, it is impossible to verify whether installations are using an affected release. In a skill that may process externally supplied content, uncertainty around parser safety is a real, though low-severity, supply-chain risk.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Jinja2 is unpinned, so deployments may consume different versions with differing security properties. Because this skill generates Markdown and shareable HTML reports, template engine behavior is security-relevant, especially if any user-controlled content is rendered into templates.

Content

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

text
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0

Unverifiable Dependency: jinja2 has 16 known advisory(ies) (CVE-2019-10906 (Jinja2 sandbox escape via string formatting); CVE-2014-1402 (Incorrect Privilege Assignment in Jinja2); CVE-2025-27516 (Jinja2 vulnerable to sandbox breakout through attr filter selecting format metho) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Jinja2 has multiple historical advisories, and without version pinning there is no assurance the deployed version includes necessary fixes. This is more relevant because the skill emits HTML reports, making the template layer part of the content-handling attack surface.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

python-docx is unpinned, so the environment may install a vulnerable or incompatible release without visibility. Since the skill accepts .docx input, parser/library security is part of the attack surface and should be kept deterministic.

Content

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

text
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0

Unverifiable Dependency: python-docx has 2 known advisory(ies) (CVE-2016-5851 (Improper Restriction of XML External Entity Reference in python-docx); CVE-2016-5851 (python-docx before 0.8.6 allows context-dependent attackers to conduct XML Exter)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

python-docx has known advisories and the lack of a pinned version prevents confirming whether a safe release is installed. Since the skill accepts .docx files, using a known-safe parser version is important when handling potentially malicious documents.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

pdfplumber is unpinned, which introduces non-reproducible builds and uncertain exposure to parser bugs. This is relevant because the skill accepts PDF files from users, so document parsing runs on potentially hostile input.

Content

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

text
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0
pytest>=8.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

beautifulsoup4 is unpinned, so future installs may pull different versions with different security or parsing behavior. Because the skill scrapes external job-posting pages, deterministic parser dependencies help reduce supply-chain uncertainty and unexpected behavior changes.

Content

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

text
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0
pytest>=8.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

httpx is unpinned, making network-facing behavior and security posture version-dependent at install time. This skill fetches remote URLs, so a vulnerable HTTP client version could expose request handling or redirect-related issues.

Content

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

text
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0
pytest>=8.0.0

Unverifiable Dependency: httpx has 2 known advisory(ies) (CVE-2021-41945 (Improper Input Validation in httpx); CVE-2021-41945 (Encode OSS httpx <=1.0.0.beta0 is affected by improper input validation in `http)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

httpx has published advisories, and the unpinned specification makes the effective security posture unknowable across installations. Because the skill performs remote fetching from user-supplied or external URLs, certainty about the HTTP client's patched status matters.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
84% confidence
Finding

pytest is unpinned, which affects reproducibility and could expose development or CI environments to dependency risk. Its impact on runtime users is lower because it is typically a test-only dependency, but it still weakens supply-chain hygiene.

Content

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

text
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0
pytest>=8.0.0

Unverifiable Dependency: pytest has 2 known advisory(ies) (CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
83% confidence
Finding

pytest has advisories and the version is not pinned, so affected installations cannot be ruled out. The risk is mostly confined to development and CI rather than end-user runtime, but it still represents avoidable supply-chain exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

Multiple functions send jd_text and related structured data to llm.chat, which is a network/data transmission operation. Although this may be aligned with the analyzer's purpose, this file itself provides no user-facing warning, logging, or explanatory comment about external processing of the supplied text.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The file's user-facing docstrings, exception messages, warnings, and comments are written entirely in Chinese, which effectively imposes a single language for interaction and diagnostics. There is no indication of user opt-in, alternative locale support, or justification that the skill is intended only for a Chinese-speaking context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code writes a partial-report.md file containing pre-scan results and error details when the LLM is unavailable. Although there is later console output for successful report generation, this failure-path write has no prior disclosure or confirmation to the user in this file, and it may persist potentially sensitive job-description-derived content unexpectedly.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.