T06 · System Persistence
- Location
scripts/setup_cron.py:30- Finding
Recurring Agent Tasks Can Be Installed Without Code-Level Consent Verification
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is transparent about its job-monitoring purpose, but it needs Review because it can install persistent scheduled agent runs and process untrusted job-posting text with insufficient containment.
Install only if you are comfortable giving this skill a sensitive job-search profile and letting it run recurring monitoring. Prefer default local modes, use dedicated revocable API keys, avoid JOBWATCH_ALLOW_HOST_CREDS unless necessary, approve only the egress destinations you need, review any RSS URLs for public trusted hosts, and know how to remove the jobwatch-* cron entries before enabling live monitoring.
scripts/setup_cron.py:30Recurring Agent Tasks Can Be Installed Without Code-Level Consent Verification
scripts/pipeline.py:157Externally Controlled Job Descriptions Are Processed by a Tool-Capable Agent Without Prompt-Injection Isolation
scripts/fetch_jobs.py:57Arbitrary RSS URLs Permit Ungated Requests to Internal or Unlisted Network Destinations
The declared description is for a full autonomous job-monitoring and notification system with privacy-sensitive data collection, third-party scraping/LLM usage, consent gating, and recurring automation. The supplied code does none of that. It only manages a local outbox file: listing queued messages and archiving the file after sending. This is a materially different primary purpose and lacks the core declared behaviors, resources, and triggers. While an outbox could be a supporting component in a larger system, this chunk by itself is not accurately represented by the declared description.
The skill explicitly supports reading credentials from environment variables and optionally reusing host OpenClaw and Telegram credentials. Any skill that can read secrets and also perform network operations creates a real exfiltration risk, especially because it processes untrusted external content and runs autonomously on a schedule.
"telegram_chat" (the allowFrom list) — comma-separated. The legacy value 1
(or true/yes/all) still grants all three. Exactly these three are readable and
nothing else; each read prints a stderr line naming the credential. Without
this variable the skill reads only the .env file you filled in yourself.
- name: JOBWATCH_HOME
required: false
description: >-
The skill is designed to send user profile data, job descriptions, notifications, and optionally archived documents to multiple third-party services, and it can also reuse host credentials. Even with documented consent gates, this creates a substantial exfiltration surface because sensitive employment data and host-linked secrets may leave the local environment during automated runs.
| **Host credentials** | the OpenClaw OpenRouter key, the `openclaw.json` Telegram bot token, and the Telegram `allowFrom` list. Only these three; the auth store is opened read-only and no other profile is read. The opt-in is **per credential** (`openrouter` / `telegram_token` / `telegram_chat`), so granting one does not grant the others. | **off** | **yes** — returns `None` / raises unless that scope is named in `JOBWATCH_ALLOW_HOST_CREDS`; each read prints a stderr warning naming the credential |
| **Scheduled task** | `setup_cron.py` appends exactly three `jobwatch-*` entries to `~/.openclaw/cron/jobs.json`, after explicit onboarding consent, writing a timestamped `.bak` of the file first and leaving pre-existing jobs untouched. `openclaw.json` and all other host configuration are never modified. | **off** | **yes** — never runs unprompted |
This skill does **not**: apply to jobs on your behalf, send messages to anyone but you, read your mail or
browser data, install packages, modify any infrastructure config beyond its own cron entries, or make
any network call to a host not listed above.
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
# JOB_PROFILE.md — 求职画像(judge 的唯一判断依据)
<!-- 复制本文件为 profile/JOB_PROFILE.md 并填写(BOOTSTRAP 入职时 agent 会带你完成)。
真实画像已被 .gitignore 排除,不会进 git。写得越具体,判级越准。 -->
## 1. Hard Background(基本盘)
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
# JOB_PROFILE.md — 求职画像(judge 的唯一判断依据)
<!-- 复制本文件为 profile/JOB_PROFILE.md 并填写(BOOTSTRAP 入职时 agent 会带你完成)。
真实画像已被 .gitignore 排除,不会进 git。写得越具体,判级越准。 -->
## 1. Hard Background(基本盘)
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
真实画像已被 .gitignore 排除,不会进 git。写得越具体,判级越准。 -->
## 1. Hard Background(基本盘)
- **Experience**: <!-- 年限 + 领域,如 "9 years in Backend & Cloud Infrastructure" -->
- **Current Role**: <!-- 只写职能,不必写公司名 -->
- **Core Stack**: <!-- 核心技术栈 -->
- **Differentiator**: <!-- 你与同级候选人的差异化优势 -->
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
真实画像已被 .gitignore 排除,不会进 git。写得越具体,判级越准。 -->
## 1. Hard Background(基本盘)
- **Experience**: <!-- 年限 + 领域,如 "9 years in Backend & Cloud Infrastructure" -->
- **Current Role**: <!-- 只写职能,不必写公司名 -->
- **Core Stack**: <!-- 核心技术栈 -->
- **Differentiator**: <!-- 你与同级候选人的差异化优势 -->
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
后端选择:env KB_BACKEND > config.json 的 kb.backend > 默认 local。
- local 零依赖,写 kb_local/ 目录 + index.jsonl(默认)
- twobrain 2brain 知识库(需要 .env 里的 TWOBRAIN_* key)
- aidigest 预留:对接自建 RAG(见模块 docstring)
"""
import os
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def _key(name):
v = os.environ.get(name)
if not v:
raise RuntimeError(f"{name} not set in .env")
return v
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def _key(name):
v = os.environ.get(name)
if not v:
raise RuntimeError(f"{name} not set in .env")
return v
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.
reads became opt-in, that phrasing over-claimed the skill's default privilege.
SKILL.md, README and the zh reference now say the token comes from your own
`.env`, with host reuse requiring `JOBWATCH_ALLOW_HOST_CREDS=1`.
- **Cron write scope was imprecise.** Docs implied `openclaw.json` might be modified.
`setup_cron.py` writes only `~/.openclaw/cron/jobs.json`, after a timestamped
backup, leaving existing jobs intact. Now stated precisely in both languages.
- **Upfront privacy warning in README**, above the install and interview sections,
The usage instructions tell the user to speak specific Chinese commands and state that the skill will then conduct an interview, while the document does not offer a language or locale choice for the interaction. This is a natural-language policy concern because it appears to prescribe a specific language by default rather than making the interaction language optional or user-selected.
The skill advertises extensive capabilities involving file access, environment-variable reads, network egress, and command execution, but it does not declare a restrictive tool scope such as permissions or allowed-tools. That leaves enforcement to documentation and operator discipline rather than platform controls, increasing the chance the agent can access broader capabilities than intended.
This manifest file contains multiple natural-language strings that require Chinese comprehension, including operational guidance and mode descriptions. That effectively forces a specific language for users or operators without any opt-in, which matches the language/locale policy violation criteria.
Line L01 presents the profile file title and instructions entirely in Chinese, indicating a language expectation for the skill artifact. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless clearly justified or optional.
该文件是 markdown,因此适用 Vague Triggers 规则。L022 将启动方式描述为对 agent 说“帮我做求职监控”,这是自然语言请求而非受限命令,文中也未给出不应触发的反例或更严格的触发范围,容易在一般职业咨询场景下与普通对话重叠。
No suspicious patterns detected.