Back to skill

Security audit

ZUGFeRD Invoice Merger

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated ZUGFeRD invoice purpose, but it ships plaintext invoice data and relies on an unverified persistent executable download, so it needs Review before installation.

Review this skill before installing. Remove the packaged temp XML invoice artifacts, verify the MustangProject JAR with a trusted checksum or signature before use, avoid running the workflows with elevated privileges, and process sensitive or untrusted PDFs only in an isolated directory where temporary files are cleaned after each run.

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

T09 · Insecure Skill Coding Practices

Error
Location
temp/extracted.xml:12
Finding

Real Customer, Banking, Tax, and Invoice Data Stored in Plaintext Artifacts

Content
View full analysis
RE0182 380 20260228 QuantX GmbH Heiko Hänsel +491604784131 Info@quantx.gmbh 207/116/00362 DE328725694 1 Überweisung DE43110101015027834960 QuantX GmbH SOBKDEB2XXX ``` The same invoice record, including the same sensitive values, is present in `temp/extracted_zugferd.xml`. ### Technical Analysis The distributed project includes runtime-generated invoice artifacts containing real-looking pers ...[truncated 1502 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/zugferd_pages_workflow.py:33
Finding

Predictable Shared Temporary Files Retain Sensitive Data and Enable Local File-Clobbering Conditions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:23
Finding

Executable MustangProject JAR Is Downloaded Without Integrity Verification

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (14)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/zugferd_pages_workflow.py (reported line 38)May include surrounding context.

python
def run_mustang(args):
    """Execute mustang.jar with Java 21"""
    cmd = ["java", "-jar", MUSTANG_JAR] + args
    env = os.environ.copy()
    env["PATH"] = "/opt/homebrew/opt/openjdk@21/bin:" + env.get("PATH", "")
    result = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=60)
    return result.stdout, result.stderr, result.returncode

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/zugferd_workflow.py (reported line 35)May include surrounding context.

python
def run_mustang(args):
    """Execute mustang.jar with Java 21"""
    cmd = ["java", "-jar", MUSTANG_JAR] + args
    env = os.environ.copy()
    env["PATH"] = "/opt/homebrew/opt/openjdk@21/bin:" + env.get("PATH", "")
    result = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=60)
    return result.stdout, result.stderr, result.returncode

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file is written entirely in German, including workflow descriptions, usage guidance, and operational notes, with no indication that users may choose another language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly justified.

Content

No source excerpt is available for this finding.

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 97)May include surrounding context.

  • GhostScript (brew install ghostscript)
  • MustangProject: ~/.openclaw/tools/mustang/mustang.jar
    bash
    mkdir -p ~/.openclaw/tools/mustang
    curl -L https://github.com/ZUGFeRD/mustangproject/releases/download/core-2.22.0/mustang.jar \
         -o ~/.openclaw/tools/mustang/mustang.jar
    

Session Persistence

Medium
Category
Rogue Agent
Confidence
81% confidence
Finding

The skill instructs users to download a JAR from the internet into a persistent user-local tools directory without any integrity verification such as a checksum, signature, or pinned provenance check. Persisting an executable artifact across sessions increases the blast radius: if the download is tampered with or later replaced, subsequent runs may repeatedly execute untrusted code.

Content

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

Install mustang.jar

bash
mkdir -p ~/.openclaw/tools/mustang
curl -L https://github.com/ZUGFeRD/mustangproject/releases/download/core-2.22.0/mustang.jar \
     -o ~/.openclaw/tools/mustang/mustang.jar

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
77% confidence
Finding

The script invokes Ghostscript on attacker-controlled PDF inputs. Ghostscript has a long history of sandbox bypass and file access vulnerabilities, so processing untrusted PDFs in-process on the host can lead to arbitrary file read/write or code execution if Ghostscript is vulnerable or misconfigured.

Content

Scanner excerpt · scripts/zugferd_pages_workflow.py (reported line 46)May include surrounding context.

python
def run_ghostscript(args):
    """Execute GhostScript (gs)"""
    cmd = ["gs"] + args
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
    return result.stdout, result.stderr, result.returncode

def validate(pdf_path):

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/zugferd_pages_workflow.py (reported line 260)May include surrounding context.

python
if not os.path.exists(MUSTANG_JAR):
        missing.append(f"mustang.jar nicht gefunden: {MUSTANG_JAR}")
    
    gs_check = subprocess.run(["which", "gs"], capture_output=True)
    if gs_check.returncode != 0:
        missing.append("GhostScript (gs) nicht installiert: brew install ghostscript")

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/zugferd_pages_workflow.py (reported line 40)May include surrounding context.

python
cmd = ["java", "-jar", MUSTANG_JAR] + args
    env = os.environ.copy()
    env["PATH"] = "/opt/homebrew/opt/openjdk@21/bin:" + env.get("PATH", "")
    result = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=60)
    return result.stdout, result.stderr, result.returncode

def validate(pdf_path):

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/zugferd_workflow.py (reported line 37)May include surrounding context.

python
cmd = ["java", "-jar", MUSTANG_JAR] + args
    env = os.environ.copy()
    env["PATH"] = "/opt/homebrew/opt/openjdk@21/bin:" + env.get("PATH", "")
    result = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=60)
    return result.stdout, result.stderr, result.returncode

def validate(pdf_path):

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The markdown explicitly states 'Germany/EU only', which is a locale restriction in natural language. While the skill is German invoicing-related, the file does not frame this as a user-selectable option or clearly explain whether this is merely applicability guidance versus a hard policy constraint.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The argument help for --invoice states it must be the PDF containing ZUGFeRD XML, implying a fixed role for that input. However, the workflow validates both provided PDFs and will swap roles if the attachment file contains the XML instead, so the documentation contradicts the actual behavior rather than merely omitting detail.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This XML file contains multiple natural-language fields in German, starting with the document note 'Rechnung' and continuing throughout the invoice text. Under the policy check for language or locale constraints, the file forces a specific language without any visible opt-in or indication that the document is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The natural-language fields in the document, such as "Rechnung" and the surrounding explanatory notes, are fixed in German. Under the policy for all file types, forcing a specific language without user opt-in or a documented region-specific justification is a locale-policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The payment-terms description is user-visible natural language and is hardcoded in German. Because no language choice or explicit locale limitation is stated in the file, this can violate the language/locale policy.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.