Back to skill

Security audit

relation-keeper

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent relationship-reminder purpose, but it automatically installs persistent reminders and stores sensitive personal relationship data with weak scoping and safeguards.

Review this carefully before installing. It is intended to remember people, events, and reminders, but that means it may persist third-party personal data such as addresses, phone numbers, birthdays, and relationship history. Install only if you are comfortable with a recurring OpenClaw cron task being created automatically, and prefer setting RELATION_KEEPER_DATA to a private user directory with restrictive permissions. Avoid storing unnecessary sensitive fields, and verify how to remove the cron task and delete the JSON data files if you stop using it.

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/utils.js:20
Finding
Sensitive Personal Data Stored Without Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils.js:20-56` **Vulnerability Type**: Plaintext sensitive-data storage with insufficient access controls **Risk Level**: Medium ### Vulnerable Code ```javascript function ensureDataDir() { const d = getDataDir(); if (!fs.existsSync(d)) { fs.mkdirSync(d, { recursive: true }); } return d; } /** 初始化默认数据目录与空数据文件 */ function initDataDir() { const d = ensureDataDir(); const defaults = { portraits: { people: {} }, past_events: { events: [] }, future_events: { events: [] }, reminders_sent: { sent: {} }, }; for (const [name, data] of Object.entries(defaults)) { const filePath = path.join(d, `${name}.json`); if (!fs.existsSync(filePath)) { fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); } } return d; } function loadJson(name) { const filePath = path.join(getDataDir(), `${name}.json`); if (!fs.existsSync(filePath)) return {}; const raw = fs.readFileSync(filePath, 'utf-8'); try { return JSON.parse(raw); } catch { return {}; } } function saveJson(name, data) { ensureDataDir(); const filePath = path.join(getDataDir(), `${name}.json`); fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); } ``` ### Technical Analysis The Skill is explicitly designed to store sensitive personal information, including phone numbers, residential addresses, birth dates, personal notes, social relationships, and historical or future events. These records are written as unencrypted JSON. The directory is created without an explicit mode such as `0700`, and files are written without an explicit mode such as `0600`. Consequently, access permissions depend on the process umask. On systems with a common umask of `022`, newly created files may be readable by other local users. The default storage location is the package's `data/` directory. Keeping personal records inside the Skill installation directory also incr ...[truncated 1320 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store data in a private user-data directory rather than inside the installed Skill directory. 2. Create the data directory with owner-only permissions: ```javascript fs.mkdirSync(d, { recursive: true, mode: 0o700 }); fs.chmodSync(d, 0o700); ``` 3. Create and maintain data files with owner-only permissions: ```javascript fs.writeFileSync(filePath, JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600, }); fs.chmodSync(filePath, 0o600); ``` 4. Use atomic writes through a private temporary file followed by `renameSync()` to reduce corruption and permission inconsistencies. 5. Warn users that these files contain sensitive personal data and should not be committed, shared, or synchronized without appropriate protection. 6. Add the data files to `.gitignore` and distribute only empty templates. 7. Consider optional encryption at rest when the threat model includes other local users, shared backups, or synchronized storage. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install.js:10
Finding
Unquoted Installation Path Embedded in a Persistent Shell Instruction<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.js:10-30` **Vulnerability Type**: Potential command injection through an unsafe shell command string **Risk Level**: Medium ### Vulnerable Code ```javascript const skillDir = path.resolve(__dirname, '..'); // 创建默认数据目录与空数据文件 const dataDir = initDataDir(); console.log('✓ 数据目录已初始化:', dataDir); const tz = process.env.RELATION_KEEPER_TZ || 'Asia/Shanghai'; const channel = process.env.RELATION_KEEPER_CHANNEL; const message = `执行以下命令并发送其输出作为提醒:cd ${skillDir} && node scripts/scan.js`; const args = [ 'cron', 'add', '--name', 'Relation Keeper 扫描', '--every', '900000', '--tz', tz, ]; if (channel && channel.includes(':')) { const [ch, to] = channel.split(':', 2); args.push('--session', 'isolated', '--message', message, '--announce', '--channel', ch, '--to', to); } else { args.push('--session', 'main', '--system-event', message, '--wake', 'now'); } ``` The installer is automatically invoked by the package lifecycle configuration: ```json "scripts": { "install:cron": "node scripts/install.js", "postinstall": "node scripts/install.js", "init": "node -e \"require('./scripts/utils.js').initDataDir(); console.log('✓ 数据目录已初始化:', require('./scripts/utils.js').getDataDir());\"" } ``` ### Technical Analysis The resolved Skill directory is interpolated directly into a command-like instruction: ```text cd <skillDir> && node scripts/scan.js ``` The path is not shell-quoted or validated. If the installation path contains whitespace, shell metacharacters, command substitutions, or control operators, the resulting instruction may be parsed as multiple shell operations. The installer does not directly pass this string to `exec`; it registers the string as an OpenClaw message or system event instructing the Agent to execute the command. Exploitation therefore depends on how OpenClaw interprets and executes scheduled instructions. If the Agent follows the instruction through a shell, an u ...[truncated 1956 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not ask an Agent to interpret and execute a dynamically constructed shell command. Register a structured executable and argument array if OpenClaw supports that mechanism. 2. Use an absolute script path and invoke Node without an intermediate `cd`, for example as distinct executable and argument fields: ```text executable: node arguments: ["/absolute/path/to/scripts/scan.js"] ``` 3. If a shell command is unavoidable, apply robust platform-specific shell quoting rather than simple string interpolation. 4. Reject installation paths containing control characters, newlines, or unsupported shell metacharacters. 5. Prefer an isolated scheduled session instead of injecting recurring system events into the main session. 6. Make installation idempotent by checking for an existing task before adding another one. 7. Provide and document an uninstall command that removes the scheduled task. 8. Avoid automatic persistence during a generic package installation where possible; require explicit user confirmation before registering the recurring task. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
声明描述的是一个较完整的社交关系管理技能,包含三大能力:人物画像、未来事件与提醒、过去经历归档。给出的代码块只对应其中第一部分,而且实现范围也较基础:本地JSON存储人物信息,支持get/list/upsert,字段包括性别、生日、出生年/日期、地址、电话、备注及事实条目。代码中没有任何日程、纪念日、提醒级别、通知、定时任务、事件归档或查询回溯逻辑。虽然facts字段可勉强记录一些经历,但这只是通用键值存储,不足以支撑声明中的约会/吃饭/游玩归档功能。因此描述明显比代码实际能力更宽,属于功能性不匹配。

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill is explicitly designed to store highly sensitive personal data such as home addresses, phone numbers, birthdays, and relationship history, and it also auto-configures reminder infrastructure via cron. Without a prominent warning and consent model, users may unknowingly enable persistent storage and automated processing of third-party personal data, creating substantial privacy, compliance, and trust risks.

Ae1

High
Category
analysis-evasion
Content
**不创建一次性提醒**,使用**一个每 15 分钟运行的 Cron** 调用 `scan.js` 扫描,如有需要提醒的内容则输出。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**不创建一次性提醒**,使用**一个每 15 分钟运行的 Cron** 调用 `scan.js` 扫描,如有需要提醒的内容则输出。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README explicitly promotes collecting and storing highly sensitive personal data such as phone numbers, home addresses, birthdays, and relationship history, but provides no privacy, consent, retention, or access-control guidance. In the context of a relationship-tracking skill, this increases the risk of misuse, overcollection, and unauthorized disclosure of personal information.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The installation instructions state that running npm install will automatically configure a recurring scan every 15 minutes, but this behavior is easy to miss and is not presented as a clear security/operational warning. Automatic creation of scheduled tasks can surprise users, cause unintended background execution, and amplify the impact of any later script misuse or notification exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill references environment variables and installation-time command execution but does not declare any explicit tool scope, permissions, or allowed-tools. That creates a transparency and least-privilege problem: users and the host agent cannot easily tell that the skill depends on environment access and setup-side execution, which can enable unintended access paths or unsafe deployment assumptions.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The skill description and examples are written entirely in Chinese and the schema constrains values with Chinese-specific examples such as gender labels and social phrases, while the configuration defaults to Asia/Shanghai. The file does not state that the skill is China-specific or offer an opt-in language/locale choice, which can violate language or locale policy expectations.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger conditions are broad enough to match ordinary conversation, causing the skill to activate and persist social data without sufficiently explicit user intent. In a skill designed to store sensitive personal information and appointments, over-triggering materially increases privacy risk by capturing names, addresses, phone numbers, and relationship details when the user may only be chatting or asking a general question.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The manifest explicitly states that the skill stores highly sensitive personal data, including birthdays, home addresses, phone numbers, and relationship history, but provides no privacy notice, retention policy, consent guidance, or handling safeguards. In a relationship-management context, this creates meaningful risk of over-collection, unexpected persistence, and exposure of third-party personal data if the platform, logs, or downstream integrations are accessed or misused.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The postinstall script automatically provisions an external cron job via `openclaw` and may immediately wake a session to emit a command-like reminder message. Triggering external scheduled behavior during installation exceeds normal local setup expectations and can cause unintended message injection or persistent automation without explicit runtime consent. In the context of a relationship-management skill that handles sensitive personal data, surprise background scheduling is more risky because it can surface reminders into chats or channels the user did not intend.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This code file contains natural-language comments and console messages in Chinese, including installation behavior descriptions and runtime notices. Under the policy, forcing a specific language without user opt-in is a locale/language policy violation because users are not offered any language selection or documented justification for the constraint.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script persists highly sensitive personal data such as address, phone number, birth date, and relationship notes to local storage with no notice, consent flow, minimization, or protection visible in this file. In the context of a 'relation-keeper' skill whose purpose is to accumulate intimate social profiles over time, silent persistence materially increases privacy risk if the host machine, backups, or shared account are accessed by others.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The file-level natural-language description is entirely in Chinese, which imposes a specific language/locale on operators or maintainers without indicating any user choice or opt-in. The policy explicitly disallows language-forcing unless the constraint is documented and justified as region-specific, which is not stated here.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The getTz function defaults to 'Asia/Shanghai' when no environment variable is set, imposing a specific locale-related setting without offering user choice in this file. This can violate language/locale policy expectations unless the region-specific default is clearly documented and justified.

Natural-Language Policy Violations

Low
Confidence
66% confidence
Finding
The README is entirely written in Chinese and all usage examples, labels, and command arguments are presented only in Chinese, with no indication that other languages are supported or that Chinese is a region-specific requirement. This can be a natural-language policy concern when a skill effectively imposes a language without opt-in or justification.

Natural-Language Policy Violations

Low
Confidence
64% confidence
Finding
The display name and description are primarily in Chinese, with no indication that users can choose their preferred language or locale. This may conflict with language-choice policy if the skill is presented to a broader audience without explicit opt-in or clear locale scoping.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The package description is written entirely in Chinese and presents the skill in a single language without indicating that the user can choose another language or that the skill is intended only for a Chinese-speaking context. Under the policy for natural-language issues, this is a locale/language constraint that is not documented as optional or justified.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This code emits user-facing help/error text only in Chinese (`用法`, `姓名`, `选项`). That imposes a specific language on users without opt-in or justification, which matches the language/locale policy concern.

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The comments describe simple initialization, but the script also constructs a message instructing execution of `node scripts/scan.js` and injects it into either the current chat or an external channel, optionally with immediate wake-up. This mismatch reduces transparency and can mislead users or reviewers about side effects, increasing the risk of unauthorized or unexpected actions at install time. Because the skill manages intimate contact and event data, covert or poorly disclosed messaging behavior is especially sensitive.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The script's usage and error messages are presented only in Chinese, with no option to select another language or locale. This is a natural-language policy concern because it forces a specific language on all users without opt-in or documented justification.

Missing User Warnings

Low
Confidence
81% confidence
Finding
This code writes JSON data to disk using fs.writeFileSync, which affects user data on the local filesystem. Although the function names and comments describe the behavior for developers, there is no user-facing confirmation, warning, or visible disclosure in this file about persistence to disk.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/install.js:35