Back to skill

Security audit

Hsk Learning

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its HSK learning purpose, but one exposed tool can read arbitrary local files instead of being limited to quiz logs.

Review before installing. This skill is not obviously malicious and does not show remote code execution or exfiltration, but it should be fixed so hsk_parse_quiz_log only reads allowed quiz-log files under a dedicated directory. Users should also understand that the vocabulary tracker scans memory Markdown files and writes derived learning reports and mastery data locally.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:429
Finding

Unrestricted Local File Read Through User-Controlled Quiz Log Path

Content
View full analysis

Vulnerability Details

File Location: index.js:429-445; file content is read at lib/parser.js:9-10
Vulnerability Type: Path traversal and unrestricted local file access
Risk Level: Medium

Vulnerable Code

javascript
// index.js:429-445
async hsk_parse_quiz_log({ filePath }) {
  try {
    const absolutePath = path.isAbsolute(filePath) 
      ? filePath 
      : path.join(__dirname, '..', '..', filePath);
    
    if (!fs.existsSync(absolutePath)) {
      return {
        success: false,
        error: `File not found: ${absolutePath}`
      };
    }
    
    const items = parseQuizLog(absolutePath);
javascript
// lib/parser.js:9-10
function parseQuizLog(filePath) {
  const content = fs.readFileSync(filePath, 'utf8');

Technical Analysis

The filePath argument is externally controlled. If it is absolute, the implementation accepts it without restriction. If it is relative, it is joined to a base directory without subsequently canonicalizing the result and confirming that it remains inside an approved quiz-log directory.

Consequently, absolute paths such as /etc/hosts and relative traversal paths containing ../ can reach files outside the directory required by the skill's declared quiz-log parsing functionality. fs.existsSync() only checks existence and does not establish authorization. The resolved path is passed directly to fs.readFileSync().

The parser does not return arbitrary raw file content verbatim. Disclosure through a successful response is constrained to file lines matching its quiz-log patterns, including bold vocabulary entries and recognized vocabulary-list formats. Nevertheless, any process-readable file is opened and parsed, matching content may be returned in structured results, and error responses can expose path or parser details. This violates least-privilege filesystem access and creates a local file disclosure primitive.

Att

...[truncated 1701 chars]

Remediation
View remediation

Remediation Suggestions

  1. Define a single approved directory for quiz-performance logs, such as the OpenClaw memory directory or a dedicated memory/quiz-logs subdirectory.
  2. Reject absolute paths supplied by callers.
  3. Resolve both the approved directory and requested target with path.resolve(), then verify that the target remains inside the approved directory using path.relative() or a separator-safe prefix check.
  4. Restrict accepted files to the expected .md extension and, where practical, the documented quiz-performance filename pattern.
  5. Use fs.statSync() or its asynchronous equivalent to require a regular file. Consider rejecting symbolic links or validating the real path with fs.realpath() to prevent symlink escapes.
  6. Do not return absolute paths, raw stack traces, or internal parser errors to callers. Log detailed diagnostics only to a protected server-side log.
  7. Prefer asynchronous, size-limited reads to reduce denial-of-service risk from very large files.

Example hardening pattern:

javascript
const allowedDir = path.resolve(__dirname, '..', '..', 'memory');

if (path.isAbsolute(filePath)) {
  return { success: false, error: 'Absolute paths are not allowed' };
}

if (!filePath.endsWith('.md') || !path.basename(filePath).includes('quiz-performance')) {
  return { success: false, error: 'Invalid quiz log filename' };
}

const candidate = path.resolve(allowedDir, filePath);
const relative = path.relative(allowedDir, candidate);

if (relative.startsWith('..') || path.isAbsolute(relative)) {
  return { success: false, error: 'Path is outside the allowed directory' };
}

const realAllowedDir = fs.realpathSync(allowedDir);
const realCandidate = fs.realpathSync(candidate);
const realRelative = path.relative(realAllowedDir, realCandidate);

if (realRelative.startsWith('..') || path.isAbsolute(realRelative)) {
  return { success: false, error: 'Path is outside the allowed directory'
...[truncated 352 chars]
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Most of the implementation aligns with the declared HSK-focused learning purpose: mastery tracking, spaced repetition, vocabulary analysis, and adaptive quiz generation are all present. However, the code also performs undeclared file-system based scanning of a memory directory and report generation, which is a broader resource-access/reporting capability not explicitly described. More importantly, the description explicitly says the skill is NOT for pronunciation practice or handwriting practice, yet the code generates listening practice quizzes and writing practice exercises. Even though the listening quiz uses imagined audio rather than actual speech processing, it is still a listening/pronunciation-adjacent learning mode outside the stated constraints. The writing quiz is directly inconsistent with the 'NOT for ... handwriting practice' limitation. Therefore the description does not fully and accurately represent the behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code does support part of the declared theme: it analyzes Chinese/CJK token exposure and categorizes tokens by HSK level. However, the declared purpose presents a broader HSK learning system centered on spaced repetition mastery tracking, adaptive quiz generation, and review management. None of those core capabilities appear in this code chunk. Instead, the actual behavior is narrower and different: it reads .md files from a memory directory, counts CJK tokens, labels them as HSK1/2/3/beyond/unknown, generates a text report, and saves that report. This filesystem-based vocabulary report generation is only partially aligned with 'analyzing Chinese language exposure,' and even there it targets Markdown memory files rather than conversations specifically. Because the primary described capabilities are largely absent and the implemented behavior is materially narrower and somewhat different, this is a mismatch.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README advertises automatic scanning of conversation logs and memory/*.md files for CJK tokens, but it does not clearly warn users that potentially sensitive personal content will be parsed as part of normal operation. In a learning/progress-tracking skill, this creates a real privacy risk because users may not expect private notes, chat history, or memory files to be inspected and transformed into derived vocabulary data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill processes memory/*.md files and conversation logs to extract CJK tokens and generate progress reports, but the user-facing description does not prominently warn that personal conversation content may be scanned. This creates a privacy and transparency issue: users may invoke the skill for learning support without realizing it inspects local memory files containing potentially sensitive text.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest says the skill is NOT for pronunciation practice, but the code exposes a listening quiz format and presents it as audio-based practice. Even though it uses text placeholders rather than real audio, this still extends the skill into listening/pronunciation-oriented training beyond the declared scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

The manifest excludes handwriting practice, but the skill generates a dedicated Writing Practice quiz mode that asks the learner to compose sentences and paragraphs. While typing is not identical to handwriting, this is a writing-production capability outside the narrow HSK vocabulary tracking and adaptive quiz scope described in the manifest's exclusions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated quiz always includes the instruction string in Chinese: "请完成所有题目,完成后发送'答案'查看正确答案。" This imposes a specific language on all users, and the file does not provide any alternative locale or opt-in mechanism.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The quiz-log parser accepts an arbitrary filePath and permits absolute paths or relative traversal outside the intended memory area, then reads and parses the file if it exists. This broad file-read capability exceeds the skill's stated purpose and can expose sensitive local files if an attacker can influence the argument.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes the skill as 'user-agnostic' yet exposes a tool that updates vocabulary tracking by scanning unspecified 'memory files'. That creates an unsafe ambiguity about data scope and consent, and could lead an agent to ingest unrelated or sensitive user data while performing learning-state updates.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Broad update-tool descriptions such as scanning memory files or processing quiz logs without clear trigger conditions can cause an agent to invoke state-changing actions too eagerly. In a skill that maintains learning records, that increases the risk of unauthorized reads, unintended data modification, and silent corruption of progress tracking.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The broader skill context says the skill is not for pronunciation practice or handwriting practice, yet the quiz tool advertises 'listening' and 'writing' formats and 'actual questions' in those categories. Those capabilities suggest practice modalities beyond the stated limits, creating a semantic mismatch between declared scope and exposed functionality.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
72% confidence
Finding

The description defines the skill strictly around HSK Chinese learning, which implies a specific language context. While this may be intentional, the file does not explicitly present this as a user opt-in language constraint or justify it as a region- or language-specific tool.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This JSON file is entirely a Mandarin vocabulary dataset sourced from a Chinese-language learning site, but it does not document that the content is intentionally Chinese-specific or scoped to a Mandarin-learning use case. Under the policy rule for language or locale constraints, hard-coded language-specific content without opt-in or justification can be a policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The function updates metadata and writes to hsk-mastery-db.json using fs.writeFileSync, which modifies persistent user study data. In this file there is no confirmation prompt, logging, or user-facing comment/docstring disclosing that the skill will overwrite the local mastery database.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The code generates and saves hsk-word-report.md into the configured memory directory using fs.writeFileSync, which modifies user or system data. While there is an internal comment about saving the file, there is no confirmation prompt, user-facing log/print, or other visible disclosure in this file that the write will occur.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The manifest description presents the skill as a Chinese learning system, which imposes a specific language context in natural-language metadata without indicating any user choice or opt-in. Under the policy, language or locale constraints should either be optional, explicitly user-selected, or clearly justified as region- or domain-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The package description states the skill is an "HSK Chinese learning system," which implies a fixed language/locale context. Under the policy rule for natural-language violations, forcing a specific language can be problematic when no opt-in or explicit justification is present in the file.

Content

No source excerpt is available for this finding.