T09 · Insecure Skill Coding Practices
- Location
scripts/collect_air_data.py:46- Finding
Disabled TLS Verification Exposes the Dirigera Bearer Token
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill matches its air-quality reporting purpose, but it needs Review because it handles a hub auth token insecurely and can modify the runtime environment automatically.
Review before installing. Use this only if you are comfortable storing living-room sensor history locally and sending detailed reports through configured email or WhatsApp tools. Before regular use, fix TLS validation or certificate pinning for the Dirigera hub, remove the automatic pip install, protect temporary report files, verify CONTACTS.json permissions and recipients, and add cron only deliberately.
scripts/collect_air_data.py:46Disabled TLS Verification Exposes the Dirigera Bearer Token
scripts/generate_chart.py:13Runtime Installation of an Unpinned Third-Party Dependency
scripts/send_report.py:126Air-Quality Report Written to a Predictable Shared Temporary File
The skill's stated purpose focuses on air-quality monitoring, but it also accesses shared contact data and sends outbound communications through external CLIs. That extra behavior increases the data-sharing and command-execution surface, and because it is not declared in permissions, users and reviewers may not realize the skill can exfiltrate report contents or contact information.
The script invokes pip through os.system using a shell command, which introduces unnecessary command-execution risk and performs code-fetching/execution at runtime. Even though sys.executable is usually trusted, runtime package installation from the network expands the attack surface and can execute unreviewed package install hooks in the current environment.
import matplotlib.dates as mdates
except ImportError:
print("matplotlib not found. Installing...")
os.system(f"{sys.executable} -m pip install matplotlib --quiet")
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
The skill advertises and documents capabilities that read/write local files, access the network, and invoke shell commands, but it does not declare any explicit tool scope or permissions boundary. This weakens reviewability and enforcement, making it easier for a broadly capable skill to access sensitive local resources or execute external commands without clear user/admin approval.
The documentation encourages sending reports by email or WhatsApp but does not clearly warn that sensor history and potentially presence-related household data will be transmitted to third-party services. Users may unknowingly share private environmental and occupancy-adjacent data outside the local system.
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.
Create ~/.openclaw/workspace/CONTACTS.json with your contact information:
{
The manifest says the skill collects temperature, humidity, PM2.5, and CO2 readings every hour, but this file's top-level documentation explicitly says to run via cron every 4 hours. That is a direct contradiction between documented intent and the declared skill behavior, not merely an omitted detail.
A charting utility should not silently modify the host environment by downloading and installing packages during normal execution. This behavior is outside the core air-quality reporting purpose, creates supply-chain exposure, and may execute package installation code without operator awareness.
The script automatically performs a package installation without explicit warning or confirmation, causing unexpected environment changes and potential network access. In a skill that only claims to generate charts, silently pulling code from package sources is risky and undermines user control and auditability.
The script reads recipient contact data from a shared workspace file outside the skill's own data boundary, creating a cross-domain trust issue. If another skill, process, or attacker can modify that file, reports could be silently redirected to an unauthorized email address or WhatsApp number, causing data exfiltration.
The script delegates data transmission to external CLI tools, expanding the trust boundary to whatever binaries named 'gog' and 'wacli' resolve at runtime. If those tools are replaced, trojaned, or PATH-hijacked, they can exfiltrate report contents, contacts, or other local data under the script's privileges.
The email-sending path transmits full report contents externally without an in-code warning or consent gate. In the context of a home-monitoring skill, this can disclose environmental and behavioral information to unintended recipients if configuration is wrong or users are unaware the action is external.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"--body-file", temp_body
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"✅ Email sent successfully to {EMAIL}")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"--body-file", temp_body
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"✅ Email sent successfully to {EMAIL}")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"--body-file", temp_body
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"✅ Email sent successfully to {EMAIL}")
The code sends detailed historical air-quality readings over WhatsApp without any built-in consent prompt or warning that data is leaving the local monitoring environment. Even if the data is not highly regulated, occupancy patterns and household conditions can be inferred from timestamps and readings, making silent external transmission a meaningful privacy issue.
This code reads a bearer token from a local credential file to authenticate to the hub. Although the file purpose is evident in code, there is no explicit user-facing disclosure in the script description or comments warning that credentials are accessed during execution.