Back to skill

Security audit

Job Hunter

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent job-alert bot, but it asks users to store a Telegram bot token and personal job-seeker data in plaintext and recommends persistent background/cron operation without enough safety guidance.

Review before installing. Use a dedicated Telegram bot token, keep config.json out of source control and backups, restrict file permissions, remove unused contact/work-history fields unless you truly need them, and add a clear way to stop/supervise the bot and cron job. Treat Telegram messages as externally rendered content until HTML escaping is fixed.

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/bot.py:80
Finding

Unescaped LinkedIn Job Data Enables Telegram HTML Injection

Content
View full analysis
{s['score']}% - " f"{j['title']}\n" f"🏢 {j['company']}\n" f"📍 {j['location']}\n" f"⏱ {yr_text}" ) ``` Job descriptions are also inserted into HTML messages without escaping: ```python if row[3]: desc = row[3][:1500] msg += f"\nDescription:\n{desc}" self.send(chat_id, msg) ``` The notification script contains the same vulnerable rendering pattern: ```python msg = ( f"{emoji.get(j['recommendation'], '⚪')} {j['score']}% - " f"{j['title']}\n" f"🏢 {j['company']}\n📍 {j['location']}\n⏱ {yr_text}" ) ``` All such messages are sent with HTML parsing enabled: ```python payload = { "chat_id": chat_id, "text": text, "parse_mode": "HTML", "disable_web_page_preview": True, } ``` ### Technical Analysis Job titles, company names, locations, and descriptions originate from externally controlled LinkedIn job listings. The scraper calls `html.unescape`, which converts encoded markup such as `<a href=...>` back into active angle-bracket syntax. These values are persisted and later concatenated directly into Telegram messages using `parse_mode: "HTML"`. Because no `html.escape` or equivalent o ...[truncated 2012 chars]
Remediation
View remediation
{s['score']}% - " f"{safe_title}\n" f"🏢 {safe_company}\n" f"📍 {safe_location}\n" f"⏱ {yr_text}" ) ``` 3. Apply the same encoding to scoring-breakdown strings if they can contain profile or external values. 4. Alternatively, remove `parse_mode: "HTML"` and send plain-text messages where rich formatting is unnecessary. 5. Validate job URLs before adding them to inline buttons. Permit only expected HTTPS LinkedIn job URLs, for example by parsing the URL and verifying the scheme, hostname, and path rather than relying solely on the scraper regex. 6. Add tests containing encoded and literal tags, malformed markup, and crafted links to ensure external content is always rendered as text. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:49
Finding

Bot Credential and Unnecessary Candidate PII Are Stored Together in Plaintext

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code chunk only implements one narrow part of the declared system: scraping LinkedIn job listings and saving basic fields locally. It does not contain Telegram bot logic, alert delivery, apply-button generation, candidate-job matching/scoring, or CV tailoring. The declared description presents a substantially broader automated job-hunting platform, while the actual code is just a scraper and local database ingester. This is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill explicitly asks for sensitive personal data, employment history, contact details, and a Telegram bot token, then stores them in a plaintext config.json without any privacy, retention, access control, or secret-handling guidance. This creates a clear risk of credential compromise, identity exposure, and leakage of highly sensitive candidate information if the project directory, logs, backups, or host are accessed by others.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs users to deploy a network-capable system that scrapes LinkedIn and interacts with Telegram, but it does not declare any explicit tool scope or permissions boundaries. In an agent ecosystem, missing scope declarations weaken policy enforcement and make it harder to constrain network actions or review whether the skill's capabilities are appropriate.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest description lists triggers such as 'find jobs for' and 'build job bot', plus broad usage text like 'helping someone find a job automatically.' These phrases are not narrowly constrained and could match ordinary conversation rather than a specific, well-bounded skill invocation context.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Running the bot with nohup creates a persistent background process outside normal interactive oversight, which can continue making network requests and processing messages indefinitely. In the context of a skill that handles credentials, user IDs, and job-search automation, this persistence increases the blast radius of misconfiguration, abuse, or unnoticed malfunction.

Content

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

7. Start the Bot

bash
nohup python3 -u bot.py > bot.log 2>&1 &

8. Set Up Daily Search (Cron)

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/bot.py (reported line 25)May include surrounding context.

python
with open(CONFIG_PATH) as f:
            self.config = json.load(f)
        self.token = self.config["telegram_bot_token"]
        self.api = f"https://api.telegram.org/bot{self.token}"
        self.authorized = set(self.config.get("authorized_users", [self.config["telegram_user_id"]]))
        self.profile = self.config.get("candidate", {})
        self.last_update_id = 0

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/notify_new_jobs.py (reported line 31)May include surrounding context.

python
with open(CONFIG_PATH) as f:
            self.config = json.load(f)
        self.token = self.config["telegram_bot_token"]
        self.api = f"https://api.telegram.org/bot{self.token}"
        self.authorized = set(self.config.get("authorized_users", [self.config["telegram_user_id"]]))
        self.profile = self.config.get("candidate", {})
        self.last_update_id = 0

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The /search command triggers scrape_and_store() after only announcing that it is 'Searching LinkedIn', but it does not disclose that the skill will perform external network requests and may transmit user or system-derived query data. For code files, network operations should have some clear user-facing warning, confirmation, or explanatory comment unless the behavior is explicitly documented as the skill's stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code explicitly treats Hebrew text as part of its parsing logic and defaults job searches to the location "Israel." This imposes a specific locale/region behavior in natural-language-relevant functionality without presenting it as an opt-in choice or documenting a justified region-specific scope in this file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The scorer gives positive points when the location contains the hard-coded country string "israel" or "remote", which embeds a geographic preference directly into decision logic without clear user consent or configuration. In a job-hunting automation skill, this can systematically bias recommendations, suppress relevant jobs in other regions, and create fairness/privacy issues if the candidate did not explicitly choose that preference.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code performs outbound HTTP requests to the Telegram Bot API containing job details and recipient identifiers. While the file has a high-level docstring, there is no explicit user-facing warning, confirmation, or clear disclosure near the network transmission that data will be sent to an external service.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.