T09 · Insecure Skill Coding Practices
- 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
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/input_parser.py:54Unrestricted URL Fetching Enables Server-Side Request Forgery and Indirect Data Disclosure
scripts/analyzer.py:8Untrusted Job Description Content Is Embedded Directly into LLM Instructions
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.
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.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Or ~/.config/jd-truth-detector/config.yaml:
base_url: https://api.deepseek.com/v1
api_key: sk-...
model: deepseek-chat
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.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
base_url: https://api.openai.com/v1
api_key: sk-...
model: gpt-4o-mini
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.
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.
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.
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.
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.
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
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.
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0
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.
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.
openai>=1.30.0
pyyaml>=6.0
jinja2>=3.1.0
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
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.
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.
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
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.
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.
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
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.
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
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.
python-docx>=1.1.0
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0
pytest>=8.0.0
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.
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.
pdfplumber>=0.11.0
beautifulsoup4>=4.12.0
httpx>=0.27.0
pytest>=8.0.0
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.
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.
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.
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.
No suspicious patterns detected.