Back to skill

Security audit

Erpclaw Publish 4.15.0 20260816 103527

Security checks for vulnerabilities and agentic risk

Overview

ERPClaw is a coherent local ERP skill, but its module installation and onboarding paths create a meaningful remote-code and sensitive-data exposure risk that users should review before installing.

Install only if you are comfortable giving this skill control over local business records, payroll data, credentials, backups, and persistent modules. Avoid real production data or module onboarding until the registry verification and module source restrictions are tightened, and treat installed expansion modules as code with the same privileges as the ERP process.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/module_manager.py:301
Finding

Fail-Open Module Registry Verification Enables Remote Payload Execution

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (505)

Tainted flow: 'req' from os.environ.get (line 229, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/module_manager.py (reported line 230)May include surrounding context.

python
for attempt in range(retries + 1):
        try:
            req = urllib.request.Request(url, headers={"User-Agent": "erpclaw"})
            resp = urllib.request.urlopen(req, timeout=timeout)
            return resp.read()
        except Exception as e:
            last_err = e

Tainted flow: 'req' from os.environ.get (line 229, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/module_manager.py (reported line 2133)May include surrounding context.

python
base = os.environ.get("ERPCLAW_GITHUB_RAW_BASE", GITHUB_RAW_BASE)
    url = f"{base}/{rel_path}"
    req = urllib.request.Request(url, headers={"User-Agent": "erpclaw"})
    with urllib.request.urlopen(req, timeout=15) as resp:
        data = resp.read()
    actual = hashlib.sha256(data).hexdigest()
    if actual != expected_hash:

Self-Modification

High
Category
Rogue Agent
Confidence
90% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · CHANGELOG.md (reported line 423)May include surrounding context.

md
### Changed
- **`erpclaw_lib/crypto.py` rewritten** to use the `cryptography` library (OpenSSL via cffi). PBKDF2-HMAC-SHA256 at 600,000 iterations (OWASP 2024). Field-level encryption uses raw AES-256-GCM with `enc:v2:` prefix. Legacy `ECRYPT01` decrypt path retained for v4.0.x backups.
- **Stripe addon: hard-removed `--api-key` flag.** `erpclaw-integrations-stripe` v2.0.1 reads credentials from the foundation credential store. Users migrate via `erpclaw migrate-credentials` (one-time read-from-DB → write-to-encrypted-store) or set fresh via `erpclaw set-credential --integration stripe --from-stdin`.
- **Lib bootstrap removed.** `_bootstrap.py` deleted. `~/.openclaw/erpclaw/lib` is now a symlink (created at `initialize-database`) to the skill-bundled location, not a self-healing copy. Eliminates the "self-modifying code at runtime" finding.
- **Foundation `SKILL.md` disclosure cleanup.** Removed 4 v4.0.1 paragraphs (Credential handling, Data protection, Module installation safety, Library self-heal) that were reading as scanner trigger surfaces while describing addon behavior or implementation details. Kept only the factual one-line Security summary.

### Removed

Self-Modification

High
Category
Rogue Agent
Confidence
90% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · scripts/erpclaw-setup/db_query.py (reported line 1155)May include surrounding context.

python
### Changed
- **`erpclaw_lib/crypto.py` rewritten** to use the `cryptography` library (OpenSSL via cffi). PBKDF2-HMAC-SHA256 at 600,000 iterations (OWASP 2024). Field-level encryption uses raw AES-256-GCM with `enc:v2:` prefix. Legacy `ECRYPT01` decrypt path retained for v4.0.x backups.
- **Stripe addon: hard-removed `--api-key` flag.** `erpclaw-integrations-stripe` v2.0.1 reads credentials from the foundation credential store. Users migrate via `erpclaw migrate-credentials` (one-time read-from-DB → write-to-encrypted-store) or set fresh via `erpclaw set-credential --integration stripe --from-stdin`.
- **Lib bootstrap removed.** `_bootstrap.py` deleted. `~/.openclaw/erpclaw/lib` is now a symlink (created at `initialize-database`) to the skill-bundled location, not a self-healing copy. Eliminates the "self-modifying code at runtime" finding.
- **Foundation `SKILL.md` disclosure cleanup.** Removed 4 v4.0.1 paragraphs (Credential handling, Data protection, Module installation safety, Library self-heal) that were reading as scanner trigger surfaces while describing addon behavior or implementation details. Kept only the factual one-line Security summary.

### Removed

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · README.md (reported line 13)May include surrounding context.

md
<p align="center">
  <img src="https://img.shields.io/badge/license-GPL--3.0-green" alt="License: GPL-3.0">
  <!-- version badge auto-synced by release/scripts/sync_facts.py (badge URL pattern) -->
  <img src="https://img.shields.io/badge/version-v4.15.0-0d9488" alt="Version v4.15.0">
  <img src="https://img.shields.io/badge/OpenClaw-skill-14b8a6" alt="OpenClaw Skill">
  <img src="https://img.shields.io/badge/database-SQLite%20%7C%20PostgreSQL-0d9488" alt="SQLite or PostgreSQL">

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The supplied code chunk is a small infrastructure utility module whose sole purpose is to resolve installation-related paths. It reads the ERPCLAW_HOME environment variable, expands a default home directory, and constructs paths to a lib directory, database file, and SKILL.md. It does not implement or expose ERP operations such as accounting, invoicing, inventory, HR, payroll, tax, reporting, audit trail, compliance, or module installation. While such a helper could support a larger ERP system, this chunk’s actual behavior is materially narrower than the declared description, so the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents the skill as a full ERP platform with extensive operational capabilities across accounting, inventory, HR, payroll, reporting, and related domains. However, the supplied code chunk is not implementing those ERP capabilities; instead, it is a discovery/helper module for listing and describing actions exposed by the skill. Its primary function is to inspect Python source files and SKILL.md, extract action names and metadata, and report whether actions are destructive. This is a materially different purpose from the declared end-user functionality. While such code could be an internal support component of a larger ERP skill, the evaluation is for whether the supplied code chunk matches the declared description, and this chunk does not directly embody the described ERP behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description presents a full multi-domain ERP platform with extensive accounting, inventory, purchasing, tax, payroll, and financial reporting capabilities. However, the provided code chunk only shows HR-focused functionality: assigning shifts, listing shift assignments, adding attendance regularization rules, applying attendance regularization by updating attendance records, and managing employee documents and expiry checks. There is no evidence in this chunk of accounting, invoicing, inventory, purchasing, tax, billing, general ledger, financial reporting, consolidation, or expansion-module behavior. This is a material description-versus-code mismatch for the supplied chunk, even though the HR-related behavior is plausibly part of the broader claimed system.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full ERP application with extensive operational/accounting capabilities. The supplied code chunk does not implement those business functions directly. Instead, it acts as a meta utility for setup/onboarding: it scans installed skills under ~/clawd/skills, inspects a SQLite database, reports installation status, recommends next modules to install, and seeds demo data by calling other modules' db_query.py scripts. While this supports an ERP ecosystem, its primary behavior is installation management and sample-data orchestration, not the broad ERP functionality claimed in the description. Therefore the description does not accurately represent this specific code chunk's behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code chunk does not implement the declared ERP application capabilities such as accounting, invoicing, inventory, payroll, reporting, or optional module installation. Instead, it contains a list of governance rules for module compliance and helper accessors over those rules. While such a constitution could support the broader ERP platform internally, the actual code's primary purpose is policy definition and validation support, which is materially different from the declared description of business-facing ERP functionality. There is no evidence here of undeclared dangerous behavior, but there is a clear description-versus-behavior mismatch for this chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The description presents the skill as a comprehensive ERP application with extensive operational domains and financial capabilities. The supplied code, however, is a maintenance/runtime command router focused on module validation, constitution article listing, table registry generation, and schema migration handlers. It also emits error messages for many actions that were moved to an addon, rather than implementing those ERP features directly. While this file may belong to a larger ERP project, the code chunk itself does not accurately reflect the declared primary functionality. That is a material description-versus-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a broad ERP application with business functions like accounting, payroll, inventory, tax, billing, and financial reporting. The supplied code does not implement those ERP business capabilities; instead, it is infrastructure code for database schema management. Its primary purpose is to compare declared schemas to the live SQLite database, generate and store migration plans, apply CREATE TABLE statements, roll back applied migrations by dropping created tables after backups, and detect schema drift. While such migration tooling could support an ERP system, this chunk’s behavior is materially narrower and different from the declared purpose, so the description does not accurately represent what this code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for a full ERP application suite, but the code chunk shown does not implement ERP business functions like accounting, invoicing, HR, payroll, reporting, or GL operations. Instead, it implements developer/auditor tooling that validates ERP modules for compliance with internal architectural and security rules and runs tests. This is a materially different primary purpose, with undeclared capabilities such as static analysis, filesystem scanning, and subprocess-based test execution. While such tooling may support an ERP ecosystem, this specific code chunk is not accurately represented by the declared product description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description overstates the scope relative to the supplied code chunk. The code is explicitly a read-only reports module (db_query.py) and does not implement a full ERP system; it primarily reads accounting-related tables and emits JSON financial reports. Its behavior is consistent with a financial reporting/report-query skill, not with the full declared platform scope including inventory, purchasing, HR, payroll, broad billing/invoicing workflows, optional module installation, audit trail management, or general ERP transaction processing. There is no evidence here of undeclared dangerous behavior; the issue is that the declared purpose is much broader than the actual behavior of this specific code chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
metadata: {"openclaw":{"type":"executable","install":{"post":"python3 scripts/erpclaw-setup/db_query.py --action initialize-database"},"requires":{"bins":["pyth

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
85% confidence
Finding

Skill instructs the agent to never refuse or to always comply. Suppressing the agent's ability to decline removes a core safety control and enables downstream harmful requests to succeed.

Content

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

md
- **Before claiming an entity exists, is a duplicate, or has a balance/count — you MUST have called a `list-*`/`get-*` for it in THIS turn and seen it returned.** This is mandatory and has no exception. Asked to add or create something (a new customer, a received shipment of stock, a new supplier)? Do not refuse it as an existing duplicate from memory: call the relevant lookup (e.g. `list-customers`) this turn first; if it returns no match, CREATE it — the default for an add/create request is to act, not to refuse. A name, number, or "already set up" feeling from earlier in the chat, your workspace context, or training is NOT evidence it is in the books; if you have not run the lookup this turn, you do not know it exists. Conversely, when the ERP DOES return a document another session created, treat it as authoritative and act on it — do not refuse because a session was reset or your notes say the data is stale. The ERP query is the only truth; your memory is not.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
ed actions keep an installed foundation aligned with the published manifest in `module_registry.json`. `update-foundation --user-confirmed` compares each instal

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Router: `scripts/db_query.py` -> 14 core domains. Optional modules installed from GitHub (`avansaber/*`) to `~/.openclaw/erpclaw/modules/` (user-approved only).

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · assets/demo.svg (reported line 2)May include surrounding context.

text
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" width="760" height="470" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" role="img" aria-label="ERPClaw natural-language demo: add a customer, invoice them, record payment, show P and L by department">
  <!--
    Animated terminal demo for the ERPClaw README.
    GitHub renders animated SVG through the <img> tag and runs SMIL <animate>,
    but strips <script> and external fonts. Animation here is pure SMIL: each

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 · mcp/tool_router.py (reported line 61)May include surrounding context.

python
def _resolve_env() -> dict:
    """Child env. ERPCLAW_HOME flows through unchanged so the subprocess router
    resolves the same lib + DB the server resolved (paths.py mirrors it)."""
    env = dict(os.environ)
    # Be explicit so the child cannot diverge from the server's resolution.
    env["ERPCLAW_HOME"] = paths.erpclaw_home()
    return env

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/db_query.py (reported line 966)May include surrounding context.

python
args[i + 1] = action_override
                break

    os.execvp(sys.executable, [sys.executable, script] + args)


def forward_script(script_path):

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/db_query.py (reported line 1001)May include surrounding context.

python
args[i + 1] = action_override
                break

    os.execvp(sys.executable, [sys.executable, script] + args)


def forward_script(script_path):

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/db_query.py (reported line 979)May include surrounding context.

python
sys.exit(1)

    args = _strip_router_flags(list(sys.argv[1:]))
    os.execvp(sys.executable, [sys.executable, script_path] + args)


def forward_module(module_name, action_override=None):

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
85% confidence
Finding

Skill instructs the agent to never refuse or to always comply. Suppressing the agent's ability to decline removes a core safety control and enables downstream harmful requests to succeed.

Content

Scanner excerpt · scripts/erpclaw-gl/db_query.py (reported line 80)May include surrounding context.

python
# appears in a shipped chart is accepted by construction — us_gaap (both copies),
# indian_coa and ca_coa_aspe together supply 21 of the types below, and
# test_the_coherence_map_accepts_every_pair_our_own_charts_ship re-derives that
# from the JSON on every run so the map can never refuse a chart we ship. That is
# the M91 lesson written down: a rule measured against the product's own data
# before it is enforced on anyone else's. (setup-chart-of-accounts inserts rows
# directly rather than through add_account, so chart loading is NOT gated by this

Ssd 3

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code explicitly decrypts employees' stored bank routing numbers and includes the plaintext value in the normal API response while only masking the account number. In plain-language terms, it instructs the system to reveal sensitive financial data to whoever can invoke the listing action, which creates a clear data-leak path even though it is framed as a display convenience.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution, suspicious.insecure_tls_verification

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
mcp/server.py:52

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/erpclaw-setup/db_query.py:2613

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/erpclaw-setup/lib/erpclaw_lib/vendor/sqlalchemy/orm/_orm_constructors.py:1142

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/erpclaw-setup/lib/erpclaw_lib/vendor/sqlalchemy/orm/clsregistry.py:533

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/erpclaw-setup/lib/erpclaw_lib/vendor/sqlalchemy/util/typing.py:274

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/erpclaw-setup/migration_runner.py:146

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/module_manager.py:1241

HTTPS certificate verification is disabled.

Warn
Code
suspicious.insecure_tls_verification
Location
scripts/erpclaw-setup/lib/erpclaw_lib/vendor/sqlalchemy/dialects/mysql/pymysql.py:32

HTTPS certificate verification is disabled.

Warn
Code
suspicious.insecure_tls_verification
Location
scripts/erpclaw-setup/lib/erpclaw_lib/vendor/sqlalchemy/dialects/postgresql/pg8000.py:69