Back to skill

Security audit

可逆关键词脱敏

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated privacy purpose, but its legacy Word document handling can invoke local Office/LibreOffice in ways that deserve review before installation.

Install only if you are comfortable running a local document-processing CLI on user-selected files. Avoid using this skill on untrusted legacy .doc files unless you convert them in a sandbox or isolated environment first, and keep mapping files, password files, and RKM_KEY values out of chats, logs, and Git.

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

Error
Location
scripts/rkm.py:827
Finding

Microsoft Word COM Conversion Opens Documents Without Disabling Macros

Content
View full analysis

Vulnerability Details

File Location: scripts/rkm.py:827-848
Vulnerability Type: Unsafe processing of active document content
Risk Level: High

Vulnerable Code

python
file_format = 16 if output_path.suffix.lower() == DOCX_SUFFIX else 0
script = r"""
$ErrorActionPreference = 'Stop'
$word = $null
$doc = $null
try {
  $word = New-Object -ComObject Word.Application
  $word.Visible = $false
  $word.DisplayAlerts = 0
  $doc = $word.Documents.Open($env:RKM_WORD_INPUT, $false, $true, $false)
  $doc.SaveAs2($env:RKM_WORD_OUTPUT, [int]$env:RKM_WORD_FORMAT)
} finally {
  if ($doc -ne $null) { $doc.Close($false) | Out-Null }
  if ($word -ne $null) { $word.Quit() | Out-Null }
}
"""
env = os.environ.copy()
env["RKM_WORD_INPUT"] = str(input_path)
env["RKM_WORD_OUTPUT"] = str(output_path)
env["RKM_WORD_FORMAT"] = str(file_format)
creationflags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
result = subprocess.run(
    [powershell, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script],

Technical Analysis

The Windows conversion path starts Microsoft Word through COM and opens the user-supplied legacy document without first setting Word's AutomationSecurity property to force-disable macros. Opening the document as read-only, hiding the Word interface, and disabling alerts do not provide a security boundary against active content.

The PowerShell process also uses -ExecutionPolicy Bypass. Although the PowerShell script itself is fixed and file paths are passed through environment variables rather than interpolated into the script, this setting does not mitigate malicious behavior originating from the document being opened.

This functionality is relevant to the declared support for legacy .doc files, but opening potentially untrusted documents in a fully privileged desktop Word process exceeds the minimum safe processing model. Conversion should occur ...[truncated 1243 chars]

Remediation
View remediation

Remediation Suggestions

  • Set Word's automation security mode before opening any document:

    powershell
    $word = New-Object -ComObject Word.Application
    $word.AutomationSecurity = 3  # msoAutomationSecurityForceDisable
    $word.Visible = $false
    $word.DisplayAlerts = 0
    
  • Prefer Protected View or another conversion mechanism that does not execute document active content.

  • Process untrusted legacy documents in a sandboxed, disposable worker with restricted filesystem access, no credentials, and no network access.

  • Consider rejecting macro-capable or legacy inputs unless the user explicitly opts into conversion after receiving a security warning.

  • Document that read-only mode does not make an untrusted Office document safe.

  • Add automated Windows tests confirming that macro execution remains disabled during COM conversion.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rkm.py:917
Finding

DOCX Archive Processing Lacks Decompression and XML Resource Limits

Content
View full analysis

Vulnerability Details

File Location: scripts/rkm.py:917-925
Vulnerability Type: Unbounded archive decompression and XML parsing
Risk Level: Medium

Vulnerable Code

python
with zipfile.ZipFile(path) as package:
    for info in package.infolist():
        if not is_docx_text_xml(info.filename):
            continue
        raw = package.read(info.filename)
        try:
            root = etree.fromstring(raw, parser)
        except Exception:
            continue

Technical Analysis

DOCX files are ZIP archives. The implementation enumerates matching XML members, fully decompresses each member into memory with package.read(), and then builds an in-memory XML tree. It does not enforce limits on:

  • Compressed or uncompressed member size
  • Total uncompressed size across relevant members
  • Compression ratio
  • Number of archive members
  • XML element count or nesting complexity
  • Aggregate memory or processing time

The configured XML parser uses resolve_entities=False, which is an appropriate defense against external-entity expansion, but it does not prevent ZIP bombs, very large XML members, or computationally expensive XML structures.

Because document scanning and masking inherently require reading document content, archive access is necessary for the declared functionality. Unrestricted decompression and parsing are not necessary and create an avoidable denial-of-service condition.

Attack Path

  1. An attacker constructs a DOCX archive containing one or more highly compressed, extremely large XML members under paths accepted by is_docx_text_xml(), such as a member beneath word/ ending in .xml.
  2. The attacker provides the file to a user for masking, scanning, verification, repair, or restoration.
  3. load_docx_text_model() calls package.read(info.filename) without checking the member's declared uncompressed size or compression ratio.
  4. Python decompresses ...[truncated 694 chars]
Remediation
View remediation

Remediation Suggestions

  • Inspect each ZipInfo before extraction and reject members exceeding a conservative uncompressed-size limit.
  • Enforce an aggregate uncompressed-size limit across all processed XML members.
  • Reject suspicious compression ratios, while handling zero-byte compressed-size values safely.
  • Limit the number of archive entries and relevant Word XML parts.
  • Parse XML incrementally where practical instead of loading every complete member and tree into memory.
  • Enforce XML depth, element-count, and text-size limits.
  • Run document parsing in a resource-constrained worker with memory and CPU limits.
  • Return a clear validation error when a document exceeds the configured safety limits.
  • Add regression tests using oversized and highly compressed DOCX fixtures.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (17)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rkm.py (reported line 522)May include surrounding context.

python
for term in terms:
        if term.strip():
            rules.append(Rule(category="K", value=term.strip(), source="term"))
    return rules


def rule_to_dict(rule: Rule) -> dict[str, str]:

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rkm.py (reported line 554)May include surrounding context.

python
for term in terms:
        if term.strip():
            rules.append(Rule(category="K", value=term.strip(), source="term"))
    return rules


def rule_to_dict(rule: Rule) -> dict[str, str]:

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rkm.py (reported line 619)May include surrounding context.

python
for term in terms:
        if term.strip():
            rules.append(Rule(category="K", value=term.strip(), source="term"))
    return rules


def rule_to_dict(rule: Rule) -> dict[str, str]:

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rkm.py (reported line 629)May include surrounding context.

python
for term in terms:
        if term.strip():
            rules.append(Rule(category="K", value=term.strip(), source="term"))
    return rules


def rule_to_dict(rule: Rule) -> dict[str, str]:

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rkm.py (reported line 542)May include surrounding context.

python
pattern = data.get("pattern")
    source = str(data.get("source") or "mapping")
    if value is not None:
        return Rule(category=category, value=str(value), source=source)
    if pattern is not None:
        return Rule(category=category, pattern=str(pattern), source=source)
    return None

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rkm.py (reported line 544)May include surrounding context.

python
pattern = data.get("pattern")
    source = str(data.get("source") or "mapping")
    if value is not None:
        return Rule(category=category, value=str(value), source=source)
    if pattern is not None:
        return Rule(category=category, pattern=str(pattern), source=source)
    return None

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
72% confidence
Finding

Copying the full parent environment into a child process can unnecessarily expose secrets such as API keys, tokens, proxy credentials, or other sensitive variables to external programs. In this skill, the danger is amplified because the child may be PowerShell/Word automation processing untrusted documents, expanding the trust boundary beyond the Python process.

Content

Scanner excerpt · scripts/rkm.py (reported line 842)May include surrounding context.

python
if ($word -ne $null) { $word.Quit() | Out-Null }
}
"""
    env = os.environ.copy()
    env["RKM_WORD_INPUT"] = str(input_path)
    env["RKM_WORD_OUTPUT"] = str(output_path)
    env["RKM_WORD_FORMAT"] = str(file_format)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs users to run a local CLI that reads files, writes masked and restored outputs, accesses environment variables such as RKM_KEY, and invokes shell commands for document conversion. However, the skill declares no explicit tool scope or permission boundaries, so an agent platform cannot enforce least-privilege access or clearly communicate those capabilities to users. In a security-focused masking skill, this omission is meaningful because it handles sensitive documents and secrets locally.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The section is titled 'Built-In Chinese Preset' and instructs users to use cn-sensitive for Chinese business documents, with extensive Chinese-only matching behavior described as the built-in preset. This natural-language guidance centers a specific language/locale without an explicit opt-in choice or clear statement that the skill is intentionally region-specific compliance tooling.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill embeds a fixed set of Chinese labels and later offers a built-in preset named "cn-sensitive", indicating the masking logic is tailored to Chinese-language content by default. The file does not present this as an explicit user locale choice or document a broader language-selection mechanism, which can violate language/locale policy requirements.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The only built-in preset is "cn-sensitive", and its regex rules are explicitly designed around Chinese organizations, names, addresses, dates, and identifiers. Because the file provides this locale-specific behavior without an explicit user language choice mechanism in the skill itself, it constitutes a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill advertises local masking/restoration but also executes external local programs to process legacy .doc files. Opening attacker-supplied Office documents through Word COM or LibreOffice materially increases the attack surface and can expose the host to parser vulnerabilities, macro-related risks, or unsafe document-processing behavior outside the Python code's control.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/rkm.py (reported line 847)May include surrounding context.

python
env["RKM_WORD_OUTPUT"] = str(output_path)
    env["RKM_WORD_FORMAT"] = str(file_format)
    creationflags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
    result = subprocess.run(
        [powershell, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", script],
        capture_output=True,
        text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/rkm.py (reported line 872)May include surrounding context.

python
target_ext = output_path.suffix.lower().lstrip(".")
    with tempfile.TemporaryDirectory(prefix="rkm-lo-") as tmp:
        tmp_dir = Path(tmp)
        result = subprocess.run(
            [executable, "--headless", "--convert-to", target_ext, "--outdir", str(tmp_dir), str(input_path)],
            capture_output=True,
            text=True,

Tainted flow: 'sealed' from os.environ.get (line 1137, credential/environment) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/rkm.py (reported line 1140)May include surrounding context.

python
sealed = dpapi_seal(password.encode("utf-8"))
    out_path = Path(args.out)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_text(base64.b64encode(sealed).decode("ascii"), encoding="utf-8")
    print(f"Sealed password file: {out_path}")
    print("Use it with: --dpapi-password-file " + str(out_path))
    print("This file can only be unsealed by the current Windows user account on this machine.")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file presents the skill name in Chinese on L2 while the short description and default prompt on L3-L4 are in English. This creates an implicit language behavior without stating whether the skill is intended for a bilingual audience or offering a user language choice, which matches the policy concern about language or locale constraints without opt-in.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The skill description focuses on masking sensitive keywords, verifying placeholders, and restoring content from an encrypted local mapping. This file additionally implements a credential-management feature for sealing and unsealing mapping passwords with Windows DPAPI, which is adjacent tooling rather than the described document-masking behavior itself.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.