Back to skill

Security audit

Auto Job Applying Agent

Security checks for vulnerabilities and agentic risk

Overview

This skill matches its resume and job-application purpose, but needs review because it can submit personal data to unvalidated job sites, exposes credentials through command usage and error paths, and weakens browser isolation.

Install only if you are comfortable giving the skill access to your Resumex resume and letting it mutate resume/job-tracker data. Keep AUTO_APPLY_MODE=false, review each job URL carefully, avoid generic or unfamiliar application sites, use a dedicated revocable Resumex API key, avoid Telegram delivery unless needed, and install Playwright in an isolated environment rather than a global Python environment.

Vulnerability Patterns
  • 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
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
job_applier.py:437
Finding

Resume PII Can Be Submitted to Unvalidated Arbitrary Destinations

Content
View full analysis
str: url_lower = url.lower() if "linkedin.com/jobs" in url_lower: return "linkedin" if "indeed.com" in url_lower: return "indeed" if "greenhouse.io" in url_lower: return "greenhouse" if "lever.co" in url_lower: return "lever" if "myworkdayjobs.com" in url_lower or "workday.com" in url_lower: return "workday" if "glassdoor.com" in url_lower: return "glassdoor" if "naukri.com" in url_lower: return "naukri" if "smartrecruiters.com" in url_lower: return "smartrecruiters" if "jobs.ashbyhq.com" in url_lower: return "ashby" return "generic" ``` ```python def _apply_generic(page, args: argparse.Namespace, url: str): """Generic heuristic applier for unknown portals.""" time.sleep(2) if _has_file_upload(page): _fill_common_fields(page, args) _output("manual_required", "Application requires file upload. Fields pre-filled where possible.", page.url) return filled = _fill_common_fields(page, args) for sel in [ "button[type='submit']", "input[type='submit']", "button:has-text('Submit')", "button:has-text('Apply')", "button:has-text('Send Application')", "*[data-testid*='submit' i]", ]: try: btn = page.locator(sel) if btn.count() > 0 and btn.first.is_visible(): btn.first.click() time.sleep(2) _output("applied", f"Generic form submitted. Fields filled: {', '.join(sorted(filled)) or 'none detected'}", page.ur ...[truncated 3723 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
send_pdf.py:31
Finding

Resumex and Telegram Credentials Are Exposed Through Process Arguments and Error Logs

Content
View full analysis
dict: """ Make a JSON HTTP request. GET by default, POST if payload is given. Raises RuntimeError on HTTP errors with the response body included. """ data = json.dumps(payload).encode("utf-8") if payload else None resolved_method = method or ("POST" if data else "GET") req = urllib.request.Request( url, data=data, method=resolved_method, headers={"Content-Type": "application/json"}, ) try: with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as resp: return json.loads(resp.read().decode("utf-8")) except urllib.error.HTTPError as exc: body = exc.read().decode("utf-8", errors="replace") raise RuntimeError(f"HTTP {exc.code} from {url}: {body}") from exc except urllib.error.URLError as exc: raise RuntimeError(f"Network error reaching {url}: {exc.reason}") from exc ``` ```python def telegram_send_message(bot_token: str, chat_id: str, text: str) -> bool: """ Send a plain text message to a Telegram chat. Automatically falls back from Markdown to plain text if formatting fails. Returns True on success. """ url = f"{TELEGRAM_BASE}{bot_token}/sendMessage" for parse_mode in ("Markdown", None): payload: dict = { "chat_id": chat_id, "text": text, "disable_web_page_preview": False, } if parse_mode: payload["parse_mode"] = parse_mode try: result = _json_request(url, payload) ...[truncated 2790 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
job_applier.py:523
Finding

Untrusted Job Pages Are Loaded With the Chromium Sandbox Disabled

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:15
Finding

Mutable Unpinned Dependencies and Browser Artifacts Create Supply-Chain Risk

Content
View full analysis
=1.42.0 requests>=2.31.0 ``` ```bash pip3 install -r {baseDir}/requirements.txt python3 -m playwright install chromium ``` ### Technical Analysis The requirements use lower-bound constraints rather than exact versions. Every future installation may therefore resolve to a newer package release that was not part of this audit. The project provides no lockfile or package hashes to verify artifact integrity. The Playwright command also downloads a Chromium browser binary through Playwright's distribution mechanism without documenting a reviewed revision or independent integrity policy. The `requests` package is listed even though the reviewed Python scripts use Playwright and Python's standard `urllib` implementation. This unnecessary package increases the dependency and transitive supply-chain surface. This is not evidence that the named packages are malicious. The vulnerability is that installation behavior is mutable and can change after review. ### Attack Path 1. A future package version or relevant distribution channel is compromised, maliciously modified, or unexpectedly incompatible. 2. The user follows the documented installation procedure. 3. `pip` resolves the newest version satisfying the broad lower-bound requirement. 4. Package installation or imported runtime code executes under the user's account. 5. The Playwright installer separately retrieves a browser artifact selected by the installed Playwright release. 6. Malicious or compromised code gains the same local privileges as the installation or Skill process. ### Impact Assessment A compromised dependency can execute arbitrary code under the installing user's privileges. Potential access includes project files, environment credentials, Agent configuration, resum ...[truncated 357 chars]
Remediation
View remediation
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 (26)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

A second description-versus-behavior mismatch is present: the skill claims end-to-end conversational job application and resume management, while the observed behavior is reportedly much narrower. Security reviewers depend on accurate descriptions to assess data access, automation, and consent boundaries; inaccurate claims undermine that process and can conceal risky flows or cause overbroad approval.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

A second description-versus-behavior mismatch is present: the skill claims end-to-end conversational job application and resume management, while the observed behavior is reportedly much narrower. Security reviewers depend on accurate descriptions to assess data access, automation, and consent boundaries; inaccurate claims undermine that process and can conceal risky flows or cause overbroad approval.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

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

md
---
name: resumex
version: 2.0.0
description: >
  Manage your Resumex resume and automatically apply to jobs — all through natural conversation.
  Fetches your live resume from Resumex, uses built-in web search to find best-matched jobs,
  presents a ranked list for your approval, auto-fills job application forms via a local
  Playwright helper script, and logs every application to the Resumex Job Tracker.
  Also handles full resume editing: experience, education, skills, projects, achievements,
  profile fields, AI tailoring, and Telegram delivery.
author: Atharva Badgujar
homepage: https://resumex.dev
repository: https://

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

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

md
### `resumex_delete_skill` — Remove skill or category

Fetch → modify skills array → PATCH back. Confirm what was removed.

---

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
91% confidence
Finding

AUTO_APPLY_MODE=true enables the agent to submit job applications in the user's name without per-job confirmation, creating a meaningful risk of unintended actions, reputational harm, and disclosure of personal data to third-party job portals. In the context of an automation skill that acts on live web forms, removing interactive approval materially increases the chance of harmful autonomous behavior even if it is user-configurable and documented.

Content

Scanner excerpt · PRIVACY.md (reported line 92)May include surrounding context.

md
By default, this skill **always asks for your approval** before submitting any job application.

If you set `AUTO_APPLY_MODE=true` in your OpenClaw environment:
- The agent will apply to **all found jobs without asking you first**
- Applications will be submitted in your name without per-job confirmation
- This setting is **irreversible per session** — once a form is submitted, you cannot undo it

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

📦 Install Guide (virtualenv — recommended)

bash
# 1. Create an isolated Python environment
python3 -m venv .venv
source .venv/bin/activate    # Windows: .venv\Scripts\activate

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 · PRIVACY.md (reported line 51)May include surrounding context.

md
#### `send_pdf.py` (372 lines)
- Makes ONE call: `GET https://resumex.dev/api/v1/agent` to fetch your resume
- Formats a plain-text resume summary
- If Telegram credentials are provided: makes one call to `https://api.telegram.org/bot.../sendMessage`
- If Telegram credentials are absent: prints the formatted resume to stdout only
- **No other network calls**

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 · SECURITY.md (reported line 44)May include surrounding context.

md
#### `send_pdf.py` (372 lines)
- Makes ONE call: `GET https://resumex.dev/api/v1/agent` to fetch your resume
- Formats a plain-text resume summary
- If Telegram credentials are provided: makes one call to `https://api.telegram.org/bot.../sendMessage`
- If Telegram credentials are absent: prints the formatted resume to stdout only
- **No other network calls**

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 · SECURITY.md (reported line 123)May include surrounding context.

md
#### `send_pdf.py` (372 lines)
- Makes ONE call: `GET https://resumex.dev/api/v1/agent` to fetch your resume
- Formats a plain-text resume summary
- If Telegram credentials are provided: makes one call to `https://api.telegram.org/bot.../sendMessage`
- If Telegram credentials are absent: prints the formatted resume to stdout only
- **No other network calls**

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SECURITY.md (reported line 70)May include surrounding context.

md
### ✅ Minimize credential scope

**Flag:** *"create and use a Resumex API key that can be revoked and has minimum permissions possible."*

**How Resumex API keys work:**
- Each key is scoped to **your account only** — no cross-account access possible

Session Persistence

Medium
Category
Rogue Agent
Confidence
70% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SECURITY.md (reported line 156)May include surrounding context.

md
| Send Telegram messages | ✅ Yes, only when you request it | ❌ Cannot read your Telegram messages |
| Log to Job Tracker | ✅ Yes, to your own Resumex account | ❌ Cannot log to another user's account |
| Access local files | ❌ No | — |
| Spawn background processes | ❌ No | — |
| Install system software | ❌ No (pip packages only, in your env) | — |
| Read other env variables | ❌ No (only the 5 listed above) | — |

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill requests and documents access to environment secrets and outbound network use, but does not declare an explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where a host may permit broader capability use than reviewers or users expect, especially because the skill handles API keys and browser-assisted submissions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The invocation examples use broad phrases such as common conversational requests, which increases the chance the skill is activated unintentionally. In this skill's context, accidental activation is more dangerous because it can fetch private resume data, search external sites, and potentially drive job application actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation condition accepts undefined "similar" phrasing, making the entry condition ambiguous and broad. That can cause the agent to enter high-impact workflows based on loosely related user text, which is risky for a skill capable of external requests and application submission.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
Save the user's answers in memory for this session. Tell the user:
> ✅ Preferences saved! I'll remember these for future searches.

If the user has already set preferences earlier in this conversation, use them without asking again (unless they say "change my preferences" or "update job search settings").

---

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

AUTO_APPLY_MODE allows the skill to skip per-job confirmation and proceed toward submitting applications in bulk. Even though the text adds a warning, this mode materially lowers the consent barrier for an irreversible external action and is especially risky in a job-application skill where wrong submissions can harm a user's reputation and privacy.

Content

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

md
If `AUTO_APPLY_MODE=true` is set in env, skip this step and apply to all automatically.

> ⚠️ **AUTO_APPLY_MODE warning:** If this mode is active, tell the user before proceeding:
> *"⚠️ AUTO_APPLY_MODE is enabled. I will apply to all [N] jobs without asking for per-job confirmation. Applications submitted this way cannot be undone. Should I continue?"*
> Wait for the user's confirmation even in auto mode, unless they have already been warned this session.

---

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

The skill transmits job application metadata to an external Resumex endpoint after every application attempt, including links, dates, locations, notes, and other activity data. While this is core functionality, it is still a real data-exfiltration surface and becomes more sensitive because it records user employment-seeking behavior and could include portal-specific notes or URLs.

Content

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

After every application attempt (success OR manual), log to the Resumex Job Tracker:

bash
curl -s -X POST https://resumex.dev/api/v1/jobs \
  -H "Authorization: Bearer $RESUMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script claims it uses no bot-detection evasion, but the launched Chromium process includes flags such as '--disable-blink-features=AutomationControlled', which are commonly used to reduce automation detectability. In a job-application automation skill, this mismatch is dangerous because it misleads reviewers and users about behavior while automating submissions to third-party sites that may prohibit such evasion.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The inline comment states there is 'no stealth, no bot-detection evasion,' yet the browser is configured with automation-masking flags earlier in the launch arguments. This creates a deceptive implementation/documentation gap that can hide policy-violating automation behavior and undermine informed consent and compliance review.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The module title and usage framing present this as a 'send_pdf' tool and 'Telegram Resume Sender', implying delivery of a PDF artifact. In reality, the implementation formats resume data into a text message, sends it with Telegram's sendMessage API, and follows up with manual instructions telling the user how to create a PDF themselves.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The script transmits resume contents, which can include sensitive personal data such as name, email, phone, location, employment history, education, and portfolio links, to Telegram's external API. In the context of a resume-management skill, this increases privacy risk because the destination is controlled by bot token and chat ID configuration, and the script prints the full resume summary to stdout regardless, potentially exposing PII to logs or downstream agents.

Content

Scanner excerpt · send_pdf.py (reported line 29)May include surrounding context.

python
# ── Constants ─────────────────────────────────────────────────────────────────

RESUMEX_API   = "https://resumex.dev/api/v1/agent"
TELEGRAM_BASE = "https://api.telegram.org/bot"
REQUEST_TIMEOUT = 15

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The browser context is hard-coded to use locale="en-US", which imposes a specific language/locale setting regardless of the user's preferences or region. This matches the policy concern for locale constraints because the file does not offer any user choice or document a justified region-specific need.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The dependency specifier for Playwright is open-ended (>=1.42.0), which allows future installs to pull in different major or minor releases with changed behavior or newly introduced vulnerabilities. In a skill that automates browser activity and job applications, uncontrolled dependency drift increases supply-chain and reliability risk, even though this file alone does not prove active exploitation.

Content

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

text
#
# Approx. disk usage after install: Playwright package ~10MB, Chromium binary ~300MB.

playwright>=1.42.0
requests>=2.31.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

requests>=2.31.0 is unpinned, so installations may resolve to different versions over time, making builds non-reproducible and potentially exposing the skill to vulnerable releases or behavioral regressions. This matters more here because the skill handles resumes, job applications, and likely personal data, so any HTTP client weakness could affect confidentiality or integrity of sensitive user information.

Content

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

text
# Approx. disk usage after install: Playwright package ~10MB, Chromium binary ~300MB.

playwright>=1.42.0
requests>=2.31.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
94% confidence
Finding

The manifest does not pin requests, and the package has multiple historical advisories, including credential-leak and transport-security issues. Because the installed version is unknown at install time, the environment could resolve to an affected release, which is more concerning in a skill that communicates with external services and may process user PII and credentials.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.