Back to skill

Security audit

TIA-OPENNESS-COMPLETE-SKILL

Security checks for vulnerabilities and agentic risk

Overview

This skill matches its stated PLC automation purpose, but it can generate, compile, and download PLC changes to real controllers without enough safety gates.

Install only in an engineering environment where PLC deployment is intentionally allowed. Treat download and full_automation as production-impacting actions: review generated SCL, compile diagnostics, project target, interface, IP address, and change authorization before running them. Prefer adding an explicit approval step, target allowlist, simulation/dry-run workflow, and pinned dependency lockfile before use near real equipment.

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
block_generator.py:23
Finding

Untrusted parameters can inject executable PLC source code

Content
View full analysis

Vulnerability Details

File Location: actions.py:93-108, block_generator.py:23-34, and templates/fb_template.txt:1-18
Vulnerability Type: PLC source-code injection through unsafe template interpolation
Risk Level: High

Vulnerable Code

actions.py:93-108:

python
plc_name = params.get("plc_name")
block_type = params.get("block_type")
block_name = params.get("block_name")
description = params.get("description", "")
number = params.get("number", 0)
language = params.get("language", "SCL")

if not plc_name or not block_type or not block_name:
    return {"success": False, "message": "Missing required parameters"}

try:
    plc_software = tia.get_plc_software(plc_name)
    scl_code = _scl_gen.generate(block_type, block_name, description)
    block = tia.create_block(
        plc_software, block_type, block_name, number, language, scl_code
    )

block_generator.py:23-34:

python
analysis = self._analyze_description(description)
template = self.env.get_template(
    f"{block_type.lower()}_template.txt"
)
code = template.render(
    block_name=name,
    description=description,
    variables=analysis.get("variables", []),
    logic=analysis.get("logic", ""),
    parameters=parameters or {}
)
return code

templates/fb_template.txt:1-18:

jinja2
FUNCTION_BLOCK "{{ block_name }}"
// {{ description }}
VAR_INPUT
    {% for var in variables if var.direction == 'input' %}
    {{ var.name }} : {{ var.type }};
    {% endfor %}
END_VAR
VAR_OUTPUT
    {% for var in variables if var.direction == 'output' %}
    {{ var.name }} : {{ var.type }};
    {% endfor %}
END_VAR
VAR
    // Internal variables
END_VAR
BEGIN
    {{ logic }}
END_FUNCTION_BLOCK

The same direct interpolation pattern is present in templates/fc_template.txt, templates/ob_template.txt, and templates/db_template.txt.

Technical Analysis

...[truncated 2356 chars]

Remediation
View remediation

Remediation Suggestions

  1. Implement strict allowlist validation for block and variable identifiers according to Siemens SCL naming rules. Reject quotes, newlines, comment delimiters, control characters, and unsupported Unicode characters.
  2. Do not insert raw descriptions into source code. Convert every line into a separately prefixed comment and reject carriage returns or other control characters.
  3. Build declarations and logic through typed source-generation functions rather than direct string interpolation.
  4. Validate block_type and language against explicit allowlists before using them as template names or dictionary keys.
  5. Parse or compile generated SCL in a non-deployment validation stage and present the complete generated source for review.
  6. Require explicit approval of the generated source before compilation and deployment.
  7. Add tests covering multiline descriptions, quotes, comment delimiters, malformed identifiers, and attempted SCL statement injection.

T09 · Insecure Skill Coding Practices

Error
Location
actions.py:137
Finding

PLC deployment can proceed without explicit approval or target allowlisting

Content
View full analysis

Vulnerability Details

File Location: actions.py:137-159, actions.py:183-202, and tia_core.py:231-276
Vulnerability Type: Insufficient safeguards around safety-critical industrial deployment
Risk Level: High

Vulnerable Code

actions.py:137-159:

python
def action_download(params: Dict[str, Any]) -> Dict[str, Any]:
    tia = get_tia(params)
    if not tia.project:
        return {"success": False, "message": "No project is open"}
    plc_name = params.get("plc_name")
    interface = params.get("interface", "PN/IE")
    ip_address = params.get("ip_address")
    password = params.get("password")

    if not plc_name:
        return {"success": False, "message": "Missing plc_name parameter"}

    try:
        plc_software = tia.get_plc_software(plc_name)
        success, result = tia.download_to_plc(
            plc_software, interface, ip_address, password
        )

actions.py:183-202:

python
def action_full_automation(params: Dict[str, Any]) -> Dict[str, Any]:
    steps = [
        ("Create project", action_create_project),
        ("Add PLC", action_add_plc),
        ("Create program block", action_create_block),
        ("Compile software", action_compile_software),
        ("Download", action_download)
    ]
    results = []
    for step_name, step_func in steps:
        res = step_func(params)
        results.append({
            "step": step_name,
            "success": res["success"],
            "message": res.get("message")
        })
        if not res["success"]:
            break
    return {
        "success": all(r["success"] for r in results),
        "steps": results
    }

tia_core.py:249-271:

python
conn_config = download_provider.Configuration
mode = conn_config.Modes.Find(interface)
if mode is None:
    raise Exception(f"Interface mode not found: {interface}")
pc_interface = mode.PcInterfa
...[truncated 2743 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the download step from full_automation; make deployment a separate, explicitly requested operation.
  2. Require a short-lived approval token bound to the project, compiled artifact digest, target identity, and expiration time.
  3. Enforce an administrator-managed allowlist of permitted interfaces, IP ranges, controller identities, and project-to-controller mappings.
  4. Discover and verify immutable device attributes before deployment rather than trusting only an IP address.
  5. Default to validation or dry-run mode and require an explicit deployment flag.
  6. Display the generated source, compile diagnostics, target identity, and planned hardware/software changes before approval.
  7. Require a second operator or change-management approval for production controllers.
  8. Separate hardware and software download permissions and avoid deploying hardware configuration unless specifically authorized.
  9. Record tamper-resistant audit logs containing the requester, target, project revision, source digest, approval identity, and outcome.
  10. Apply network segmentation and a least-privilege TIA Openness service account so the Skill can reach only approved engineering targets.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Open-ended dependency constraints permit unreviewed package versions

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-2 and SKILL.md:30-31
Vulnerability Type: Non-reproducible and insufficiently controlled dependency installation
Risk Level: Medium

Vulnerable Code

requirements.txt:1-2:

text
pythonnet>=3.0.0
jinja2>=3.0.0

SKILL.md:30-31:

bash
pip install pythonnet jinja2

Technical Analysis

Both dependencies use open-ended minimum-version constraints, while the installation instructions do not specify versions, hashes, an approved package index, or a lock file. As a result, installations performed at different times may resolve to different package releases that were not part of the audited project.

This is particularly sensitive for pythonnet, which integrates Python with the .NET runtime and loads assemblies into the process. A compromised or malicious dependency release would execute with the same operating-system and TIA Openness privileges as the Skill.

The audit found no evidence that the currently named packages are malicious. The issue is that the dependency policy does not ensure that future installations use reviewed artifacts.

Attack Path

  1. An operator follows the documented installation command or installs from requirements.txt.
  2. The package resolver queries its configured index and selects the newest version satisfying the open-ended constraint.
  3. A compromised package release, compromised index response, or otherwise unreviewed future version is downloaded.
  4. Package installation hooks or imported package code execute on the engineering workstation.
  5. The code runs with the privileges of the account operating the Skill, potentially including TIA Openness access.

Exploitation depends on compromise of the package distribution path or publication of a harmful release satisfying the declared package names and version constraints.

Impact Assessment

A malicious dependency could execut ...[truncated 444 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every direct dependency to an exact reviewed version.
  2. Generate and commit a lock file that includes resolved transitive dependencies.
  3. Use package hashes and install with pip --require-hashes.
  4. Configure installations to use an approved internal mirror or explicitly trusted package index.
  5. Verify package provenance and signatures where supported.
  6. Perform software-composition analysis and vulnerability scanning before dependency updates.
  7. Update the documentation so its installation command uses the locked requirements rather than unconstrained package names.
  8. Test dependency upgrades in an isolated engineering environment before approving them for systems with PLC access.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

声明描述的是一个“完整 PLC 自动化技能”,范围覆盖 TIA Openness API 驱动的项目管理、硬件配置、SCL 编程、编译和下载。而实际代码块只包含 SCLGenerator,其行为是:分析自然语言描述中的少量关键词(输入/输出、电机/泵/阀、启动/停止/控制),再通过 Jinja2 模板渲染生成 SCL 文本。代码没有出现任何 TIA Openness 相关调用、PLC 工程对象操作、硬件组态、编译任务、在线下载、设备连接或工程生命周期管理逻辑。因此,代码的实际主要用途明显窄于且不同于声明用途,属于实质性描述不符。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

声明描述的是一个功能完整的 PLC 自动化技能,覆盖从项目创建到硬件配置、程序编写、编译下载的完整流程。但提供的代码片段只是一个硬件配置辅助数据表,保存 CPU 和模块的字符串目录路径。它与“硬件配置”这一子能力部分相关,但不足以支持声明中的主要能力,也没有显示任何自动化操作、API 调用、项目管理、代码生成或下载行为。因此描述与实际代码行为存在明显不匹配,且实际功能范围显著更窄。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares capabilities that imply file-writing and project manipulation but does not define any explicit tool scope or permission boundaries. In an automation context tied to engineering projects, missing scope constraints increases the chance of unintended file modification or broader-than-expected actions by an agent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill advertises PLC download and one-click end-to-end execution without safety warnings, guardrails, or mention of live-equipment impact. In industrial automation, encouraging deployment actions without explicit confirmation, simulation checks, or environmental separation can lead to unsafe changes on production systems and physical process disruption.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The download action can deploy logic directly to a PLC using caller-supplied parameters without any explicit confirmation, safety interlock, environment check, or dry-run mode. In an industrial automation skill, this is dangerous because a mistaken, unauthorized, or automated invocation can change live controller behavior and potentially disrupt processes or create unsafe physical conditions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module docstring states the skill as a Chinese-language code generator, and the parser later relies on Chinese keywords such as “输入”, “输出”, “启动”, and “停止” to function correctly. This effectively imposes a language/locale constraint without any visible opt-in or documented user choice, which matches the policy concern for forced language behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

This is a plain text file, so vague-trigger checks apply. The notes describe behavior and prerequisites, but they do not define any explicit trigger phrases, scope constraints, or exclusion conditions, making invocation boundaries unclear.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Natural-language policy checks apply to all file types. The operational guidance is presented only in Chinese, which can impose a language choice on users without documenting that this is region-specific or offering an alternative.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The example response schema uses a Chinese-only message string literal ("操作结果描述"), which implies the skill's natural-language output is fixed to a specific language. There is no indication in this file that the user can choose the language or that the skill is intentionally limited to a Chinese locale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The method performs direct PLC deployment of hardware and software changes without any explicit confirmation, dry-run gate, authorization check, or safety interlock. In an industrial automation context, unintended or unauthorized downloads can alter live control logic, disrupt operations, damage equipment, or create personnel safety hazards.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

Line L19 contains a Chinese description string, while the rest of the workflow is in English and there is no indication that the skill is intentionally region-specific or that users can choose the language. This can violate language/locale policy expectations because the skill implicitly forces one locale for part of its user-facing content without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The natural-language content of the skill is presented in Chinese, and the file does not state that language selection is optional or user-configurable. If organizational policy requires not forcing a specific language without opt-in, this is a locale/language 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 module docstring describes the skill entirely in Chinese ("OpenClaw技能", workflow description) with no indication that users can choose another language or locale. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Natural-language strings throughout the file, including docstrings and returned user messages, are hardcoded in Chinese with no indication of locale selection or opt-in. This can violate language/locale policy when a skill forces a specific language experience without giving the user a choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The natural-language description is written only in Chinese, which may impose a language/locale constraint without any indication of user opt-in or a documented region-specific requirement. Under the policy rule, fixed language usage can be a violation when no choice or justification is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The value on L6 is written in Chinese ("自动创建的项目") while the rest of the file uses English identifiers, which indicates a locale-specific language choice embedded in the skill file. There is no indication that the user can choose the language or that a Chinese-only locale is required for this skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The natural-language description is provided only in Chinese ("主程序循环"), which may impose a language choice on users without any indication of opt-in or locale-specific justification. Under the language/locale policy check, this can be a policy concern when the skill does not document that it is intended specifically for Chinese-speaking users.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency pythonnet is specified with a lower bound only, which makes builds non-reproducible and allows installation of different versions over time, including versions with future regressions or supply-chain issues. In an automation skill that interfaces with TIA Openness and PLC engineering workflows, dependency drift can affect systems that interact with industrial control environments, increasing operational and security risk.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
pythonnet>=3.0.0
jinja2>=3.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency jinja2 is not pinned to an exact version, so installations may resolve to different releases with different security properties. Because Jinja2 has a history of sandbox and template-related security advisories, leaving the version open increases the chance that a vulnerable or incompatible release is installed in downstream environments.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
pythonnet>=3.0.0
jinja2>=3.0.0

Unverifiable Dependency: jinja2 has 16 known advisory(ies) (CVE-2019-10906 (Jinja2 sandbox escape via string formatting); CVE-2014-1402 (Incorrect Privilege Assignment in Jinja2); CVE-2025-27516 (Jinja2 vulnerable to sandbox breakout through attr filter selecting format metho) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
96% confidence
Finding

Jinja2 has multiple known advisories, and because the manifest does not pin a version, it is not possible to verify whether the installed release is affected. In a skill that may generate code or configuration artifacts from templates, use of a vulnerable templating library could expose users to template sandbox escape or related code-execution risks depending on how templates are sourced and rendered.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This plain-text template includes a hard-coded Chinese comment ('内部变量'), which imposes a specific language in generated output. The file provides no user opt-in, language selection, or documented region-specific reason for this locale choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template includes fixed Chinese comment text such as '主程序循环' and '调用功能块示例', which imposes a specific language in generated content. This is a natural-language locale choice without any indication of user opt-in or documented regional constraint.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · tia_core.py (reported line 285)May include surrounding context.

python
try:
            from Siemens.Engineering import UmacUserType
            if enum_type_name == "UmacUserType":
                return getattr(UmacUserType, value_name)
        except:
            pass
        raise ValueError(f"无法获取枚举 {enum_type_name}.{value_name}")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module docstring is written only in Chinese ("辅助工具函数"), which reflects a fixed language choice in natural-language content. Under the stated policy, forcing a specific language without user opt-in or justification can be a locale-policy violation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.