Back to skill

Security audit

Shadow AI Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local dashboard generator, but it handles sensitive employee monitoring data with under-disclosed network dependency and weak output protections.

Install only if you are comfortable reviewing the code and handling the generated JSON/HTML as sensitive employee monitoring records. Use approved telemetry sources, obtain appropriate workplace notice or legal review, restrict access to outputs, avoid opening reports with untrusted input, and consider bundling Chart.js locally plus adding sanitization before using real organizational data.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_dashboard.js:779
Finding
Stored HTML and JavaScript Injection Through Untrusted Dashboard Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_dashboard.js:19, 167, 692, 776-784, 870, 987-999` **Vulnerability Type**: Stored HTML/JavaScript injection **Risk Level**: High ### Vulnerable Code The generator accepts an arbitrary JSON file without schema validation or content sanitization: ```javascript const data = JSON.parse(fs.readFileSync(dataPath, 'utf8')); ``` Input values are interpolated directly into HTML contexts: ```javascript <title>Shadow AI Monitor - ${company}</title> ``` ```javascript <p class="subtitle">${company} - Employee AI Tool Usage Report</p> ``` ```javascript ${recentEvents.map(event => ` <tr class="${event.risk.toLowerCase()}-risk"> <td>${new Date(event.timestamp).toLocaleString()}</td> <td>${event.employee}</td> <td>${event.tool}</td> <td>${event.dataCategory}</td> <td><span class="risk-badge ${event.risk.toLowerCase()}">${event.risk}</span></td> </tr> `).join('')} ``` Input-derived data is also serialized directly into an inline script: ```javascript const employeeDrilldown = ${JSON.stringify(employeeDrilldown)}; ``` The browser-side modal then converts input-derived values into HTML and assigns them to `innerHTML`: ```javascript const eventsHTML = data.topRiskyEvents.map(event => ` <div class="event-item ${event.risk.toLowerCase()}"> <div><strong>${event.tool}</strong> - ${event.category}</div> <div class="event-meta"> <span>📅 ${event.date}</span> <span class="risk-badge ${event.risk.toLowerCase()}">${event.risk} Risk</span> </div> </div> `).join(''); document.getElementById('modalEvents').innerHTML = eventsHTML; ``` ### Technical Analysis The input file path is supplied through `process.argv[2]`, and all parsed fields are treated as trusted. No schema enforcement, type checking, HTML escaping, or JavaScript-context escaping is performed before input-derived values are inserted into the generated document. Values such as `company`, `event.em ...[truncated 2361 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define and enforce a strict schema for the input document before generating HTML: - Require expected object and array structures. - Enforce primitive types and reasonable length limits. - Restrict `risk` to an explicit enumeration such as `Low`, `Medium`, or `High`. - Reject unexpected properties where practical. 2. Apply context-specific output encoding to every value inserted into HTML text, attributes, CSS, or JavaScript. A basic HTML text encoder should at least encode `&`, `<`, `>`, `"`, and `'`. 3. Do not construct the modal with `innerHTML`. Create DOM elements and assign untrusted values through `textContent`: ```javascript const tool = document.createElement('strong'); tool.textContent = event.tool; const category = document.createTextNode(` - ${event.category}`); container.append(tool, category); ``` 4. Avoid placing serialized user data inside an executable inline script. Prefer a separate JSON file fetched and parsed as data. If inline JSON is necessary, place it in a non-executable element such as: ```html <script id="dashboard-data" type="application/json">...</script> ``` The serialized content must still escape HTML parser-sensitive characters, including `<`, `>`, `&`, U+2028, and U+2029. In particular, replace `<` with `\u003c` so that `</script>` cannot terminate the element. 5. Add a restrictive Content Security Policy. After removing inline handlers and inline scripts, use a policy similar to: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'none'; base-uri 'none'; object-src 'none'"> ``` 6. Add regression tests containing payloads in every string field, including: - `<img src=x onerror=alert(1)>` - `</script><script>alert(1)</script>` - Quotes, ampersands, angle brackets, and Unicode line separators Verify that these value ...[truncated 80 chars]

T08 · Insecure Dependencies

Warning
Location
scripts/generate_dashboard.js:168
Finding
Remote Chart.js Execution Without Subresource Integrity<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_dashboard.js:168` **Vulnerability Type**: Unprotected third-party JavaScript dependency **Risk Level**: Medium ### Vulnerable Code ```html <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script> ``` ### Technical Analysis Every generated dashboard loads and executes JavaScript from a third-party CDN when the report is opened with network access. Although a Chart.js version is specified, the resource has no Subresource Integrity hash. The browser therefore has no cryptographic mechanism to verify that the received script is the artifact reviewed or expected by the project. The generated report may contain employee activity, sensitive data-category labels, usage patterns, and compliance information. Remote JavaScript executes in the same page context and can inspect or modify that information. This behavior also conflicts with the documentation's assertion that processing is entirely local and that no external API calls occur. Opening the report creates an external dependency request even though generation itself is local. ### Attack Path 1. A user generates a dashboard through the documented workflow. 2. The user opens `shadow-ai-dashboard.html` while network access is available. 3. The browser requests Chart.js from `cdn.jsdelivr.net`. 4. If the CDN, package publication path, account, or delivery infrastructure serves a modified artifact, the browser accepts it because no integrity hash is declared. 5. The modified JavaScript executes in the dashboard page. 6. The malicious dependency reads or alters dashboard information and may transmit it to an attacker-controlled endpoint. ### Impact Assessment A compromised remote dependency can execute arbitrary browser-side JavaScript in every generated dashboard opened while the affected artifact is being served. It can: - Read the report's employee activity and compliance data from the DOM or page variab ...[truncated 429 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle a reviewed Chart.js distribution file with the skill and reference it locally. This is the preferred approach because it permits offline operation and removes runtime reliance on a mutable third-party service. 2. If a CDN remains necessary, calculate and specify a valid Subresource Integrity hash: ```html <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js" integrity="sha384-REPLACE_WITH_VERIFIED_HASH" crossorigin="anonymous"></script> ``` The hash must be generated from and checked against the exact reviewed artifact. 3. Use an immutable, explicitly versioned resource and establish a controlled process for dependency updates, including checksum verification and security review. 4. Apply a Content Security Policy that restricts scripts and network connections to the minimum required origins. If the dependency is bundled locally, use `script-src 'self'` and disable unnecessary outbound connections with `connect-src 'none'`. 5. Update `SKILL.md` to disclose any remaining runtime network dependency. Do not claim that the dashboard makes no external calls while it loads code from a CDN. 6. Add an offline test confirming that generated dashboards remain functional without network access. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (11)

Ae1

High
Category
analysis-evasion
Content
node scripts/generate_demo_data.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/generate_demo_data.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/generate_dashboard.js shadow-ai-data.json
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Session Persistence

Medium
Category
Rogue Agent
Content
Manual:
```bash
mkdir -p ~/.openclaw/skills
cd ~/.openclaw/skills
# Download and extract skill files
```
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.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs users to monitor Slack/Teams/Email for AI-tool mentions and log that data for reporting, but does not warn about employee privacy, notice/consent, retention limits, or legal review. In an enterprise setting, this can normalize workplace surveillance and collection of sensitive communications data without appropriate governance, potentially creating compliance and privacy exposure.

Ssd 3

Medium
Confidence
90% confidence
Finding
The documented workflow directs users to collect employee AI-usage signals from internal communications and retain them in JSON for later dashboarding. Storing behavioral data tied to employees can expose sensitive workplace activity patterns and, if the underlying messages include confidential content, may expand the blast radius of any later disclosure or misuse.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The skill claims there are "No External API Calls," but elsewhere documents loading Chart.js from jsDelivr CDN. That discrepancy is security-relevant because opening the generated dashboard causes the browser to fetch third-party code, which can leak access metadata and introduces supply-chain risk if the CDN-hosted script is altered or unavailable.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The dashboard builds named employee drill-down views with per-person risk breakdowns and recent risky events, which exceeds a high-level aggregate monitoring/dashboard purpose and materially increases privacy exposure. If the HTML file is shared, copied, or viewed by unauthorized staff, it reveals sensitive behavioral and potentially regulated employee activity data.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The generated dashboard loads Chart.js from a public CDN even though the tool is positioned as a local/offline report generator. Opening the report causes a network request that can disclose report access metadata and introduces supply-chain and integrity risk if the external dependency is unavailable or tampered with.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script writes a local HTML file containing employee names, risk levels, and activity details without any warning, access control, or protective handling. Because the output is an easily shareable standalone file, sensitive workforce-monitoring data can be exposed through normal file handling, email forwarding, shared drives, or screenshots.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The HTML output is explicitly marked with lang="en" and the interface strings throughout the dashboard are English only. This imposes a specific language/locale without opt-in or configuration, which matches the policy concern for forced language selection.

Static analysis

No suspicious patterns detected.