Back to skill

Security audit

OpenClaw Wallpaper

Security checks for vulnerabilities and agentic risk

Overview

This wallpaper chat skill has a coherent purpose, but it exposes unauthenticated local network services, embeds a gateway token, and retains chat/image data in ways users should review before installing.

Review and harden this skill before installing: bind services to 127.0.0.1, remove the embedded gateway token, require a per-install auth token, restrict CORS, fix the UI file server path handling, and understand that conversations and images may remain on disk even after using clear.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
wallpaper-server.js:18
Finding

Unauthenticated Network-Exposed Bridge Grants Access to the OpenClaw Agent

Content
View full analysis
{ res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (parsedUrl.pathname === '/chat' && req.method === 'POST') { await handleChat(req, res); return; } if (parsedUrl.pathname === '/stream' && req.method === 'POST') { await handleStream(req, res); return; } if (parsedUrl.pathname === '/clear' && req.method === 'POST') { // Request is processed without authentication. } }); server.listen(config.serverPort, config.serverHost, () => { // Server starts on all configured interfaces. }); ``` The bridge subsequently makes privileged Gateway requests: ```javascript const options = { hostname: '127.0.0.1', port: config.gatewayPort, path: '/v1/chat/completions', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.gatewayToken}`, 'x-openclaw-agent-id': config.agentId, 'Connection': 'keep-alive' }, agent: httpAgent }; ``` ### Technical Analysis The bridge listens on `0.0.0.0`, making port 8765 reachable through every available network interface unless an external firewall blocks it. The `/chat`, `/stream`, and `/clear` endpoints do not authenticate callers. ...[truncated 1761 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
wallpaper-server.js:13
Finding

Hard-Coded OpenClaw Gateway Bearer Token

Content
View full analysis
{ gatewayHealthy = res.statusCode === 200; resolve(gatewayHealthy); }); ``` ### Technical Analysis A live-looking bearer credential is embedded directly in distributed source code. Secrets committed to source must be treated as compromised because they can be recovered from the package, source history, backups, caches, or any installed copy. The same credential authorizes chat completion requests and Gateway health checks. There is no per-installation secret generation or external protected configuration. Although the requests target `127.0.0.1`, the token can still be abused by local processes, by users who receive the package, or against another reachable Gateway configured with the same credential. ### Attack Path 1. An attacker downloads or obtains an installed copy of the Skill. 2. The attacker reads `wallpaper-server.js`. 3. The attacker extracts the bearer token. 4. The attacker tests the token against a local or otherwise reachable OpenClaw Gateway. 5. If accepted, the attacker sub ...[truncated 440 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
wallpaper-server.js:68
Finding

Conversation History and Images Are Stored in Plaintext and Are Not Deleted by the Clear Endpoint

Content
View full analysis
body += chunk); req.on('end', () => { try { const data = JSON.parse(body); const sessionId = data.sessionKey || 'default'; conversationHistory.delete(sessionId); console.log(`[${new Date().toLocaleTimeString()}] Cleared history for session: ${sessionId}`); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true })); } catch (error) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Invalid request' })); } }); return; } ``` Messages and images are inserted into persistent history: ```javascript if (image) { const base64Data = image.includes(',') ? image.split(',')[1] : image; userContent = [ { type: 'text', text: message || 'Please inspect this image' }, { type: 'image_url', image_url: { url: `data:${imageType};base64,${base64Data}` } } ]; } else { userContent = message; } history.push({ role: 'user', content: userContent }); ``` The history is written and loaded as plaintext JSON: ```javascript function saveSession(sessionId) { const history = conversationHistory.get(sessionId); if (!history) return; const filePath = getSessionFilePath(sessionId); try { fs.writeFileSync(filePath, JSON.stringify(history, null, 2), 'utf-8'); } catch (e) { console.error(`Session save failed [${sessionId}]:`, e.message); } } function loadSession(sessionId) { const filePath = get ...[truncated 1806 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
wallpaper-ui/ui-server.js:15
Finding

Path Traversal in the Bundled UI Static-File Server

Content
View full analysis
{ let file = req.url === '/' ? '/index.html' : req.url; const filePath = DIR + file; const ext = path.extname(filePath); fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(404); res.end('Not found'); return; } res.writeHead(200, { 'Content-Type': MIME[ext] || 'text/plain' }); res.end(data); }); }); server.listen(PORT, () => console.log(`UI server: http://localhost:${PORT}`)); ``` ### Technical Analysis The server concatenates the raw request URL directly to a filesystem base path. It does not parse the pathname, decode it safely, normalize it, or confirm that the resolved path remains inside `DIR`. Traversal components such as `..` can therefore cause filesystem resolution outside the intended wallpaper directory. Query strings are also left in the path, demonstrating that the value is not being treated as a validated pathname. No host is supplied to `server.listen`. Node.js therefore listens on an unspecified address, commonly exposing the server through available IPv6 and IPv4 interfaces rather than restricting it to loopback. ### Attack Path 1. The user runs `wallpaper-ui/ui-server.js`. 2. The static server becomes reachable on port 8080. 3. An attacker sends a URL containing directory traversal components. 4. The code concatenates the request URL with `DIR`. 5. The operating system resolves the resulting path outside the intended UI directory. 6. If the process account can read the target file, its contents are returned in the HTTP response. ### Impact Assessment An attacker may re ...[truncated 300 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
wallpaper-server.js:166
Finding

Unbounded Request and Base64 Image Buffering Enables Denial of Service

Content
View full analysis
body += chunk); req.on('end', async () => { const data = JSON.parse(body); }); ``` The stream endpoint additionally retains a base64 image in conversation history: ```javascript const data = JSON.parse(body); const message = data.message || ''; const userName = data.userName || 'User'; const sessionId = data.sessionKey || 'default'; const image = data.image; const imageType = data.imageType || 'image/jpeg'; let userContent; if (image) { const base64Data = image.includes(',') ? image.split(',')[1] : image; userContent = [ { type: 'text', text: message || 'Please inspect this image' }, { type: 'image_url', image_url: { url: `data:${imageType};base64,${base64Data}` } } ]; } else { userContent = message; } history.push({ role: 'user', content: userContent }); ``` ### Technical Analysis The server buffers complete request bodies in JavaScript strings before parsing them. There is no maximum `Content-Length`, streamed byte counter, image-size limit, message-length limit, concurrency limit, or rate limit. Base64 encoding increases image size, and the complete encoded value is inserted into history and later serialized to disk. A single payload can therefore consume memory multiple times: as incoming chunks, the combined body string, parsed JSON, history content, serialized request data, and persisted JSON. This issue is especially exploitable because the bridge is unauthenticated and listens on all interfaces. ### Attack Path 1. An attacker connects to port 8765. 2. The attacker submits a very large or indefinitely streamed POST body to `/stream`, `/chat`, or `/clear`. 3. Th ...[truncated 783 chars]
Remediation
View remediation
{ received += chunk.length; if (received > MAX_BODY_BYTES) { res.writeHead(413, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Payload too large' })); req.destroy(); return; } body += chunk; }); ``` 2. Apply lower limits to text-only endpoints and explicit decoded-byte limits to images. 3. Validate image MIME types and file signatures rather than trusting `imageType`. 4. Limit concurrent requests and model streams per authenticated client. 5. Add IP- or token-based rate limiting. 6. Configure request header, body, inactivity, and total-processing timeouts. 7. Avoid persisting base64 image data unless required; use bounded temporary storage with cleanup where necessary. 8. Cap per-session and total storage usage. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:24
Finding

Unpinned Global npm Installation Creates Supply-Chain Exposure

Content
View full analysis
Remediation
View remediation
clawhub@ ``` 2. Publish and verify expected package integrity hashes or signed release artifacts. 3. Document the expected npm publisher and official package source. 4. Prefer project-local installations with a committed lockfile over global installation where supported. 5. Review lifecycle scripts and transitive dependencies before approving a release. 6. Use a trusted registry configuration and disable unnecessary lifecycle scripts where operationally possible. 7. Update pinned versions through a controlled security-review process rather than automatically resolving the latest release. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
Findings (40)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This mismatch is more serious because it includes exposure of a network server/API, handling of user-supplied images, and mention of a hardcoded gateway token. Undisclosed server exposure and embedded credentials can directly increase attack surface and risk unauthorized access to the local AI gateway or sensitive user content.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This mismatch is more serious because it includes exposure of a network server/API, handling of user-supplied images, and mention of a hardcoded gateway token. Undisclosed server exposure and embedded credentials can directly increase attack surface and risk unauthorized access to the local AI gateway or sensitive user content.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

This mismatch is more serious because it includes exposure of a network server/API, handling of user-supplied images, and mention of a hardcoded gateway token. Undisclosed server exposure and embedded credentials can directly increase attack surface and risk unauthorized access to the local AI gateway or sensitive user content.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

This mismatch is more serious because it includes exposure of a network server/API, handling of user-supplied images, and mention of a hardcoded gateway token. Undisclosed server exposure and embedded credentials can directly increase attack surface and risk unauthorized access to the local AI gateway or sensitive user content.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This mismatch is more serious because it includes exposure of a network server/API, handling of user-supplied images, and mention of a hardcoded gateway token. Undisclosed server exposure and embedded credentials can directly increase attack surface and risk unauthorized access to the local AI gateway or sensitive user content.

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

md
编辑 `wallpaper-server.js` 顶部的配置:

Memory Manipulation

High
Category
Memory Poisoning
Confidence
92% confidence
Finding

The /clear endpoint accepts any POST request, has permissive CORS (Access-Control-Allow-Origin: *), and performs no authentication or origin validation before deleting conversation history for an arbitrary sessionKey. A malicious local webpage or process could trigger cross-origin requests to erase user context, causing loss of integrity/availability of stored conversations and enabling nuisance or targeted disruption.

Content

Scanner excerpt · wallpaper-server.js (reported line 71)May include surrounding context.

js
return;
    }
    
    // Clear history endpoint
    if (parsedUrl.pathname === '/clear' && req.method === 'POST') {
        let body = '';
        req.on('data', chunk => body += chunk);

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 · wallpaper-ui/index.html (reported line 10)May include surrounding context.

html
</head>
<body>
    <div class="world">
        <!-- 星空背景 -->
        <div class="stars-bg"></div>
        <div class="stars-bg stars2"></div>
        <div class="stars-bg stars3"></div>

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The request URL is concatenated directly into a filesystem path with no normalization or path traversal protection. An attacker can potentially request paths like '/../...' or encoded traversal variants to read files outside the intended wallpaper directory, turning this into arbitrary local file read via localhost.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file states that conversation history is saved to a file, which affects user data retention and privacy. The entry presents the behavior as a feature but does not include any warning or disclosure about what data is stored, where it is stored, or privacy implications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The markdown lists an automatic installation script and support for launching on system startup, both of which can affect system integrity and persistence. These behaviors are presented without any cautionary note or disclosure to users about the changes made to their environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill documentation describes networked behavior and local server components, but it does not declare any explicit tool scope or permissions. In a skill ecosystem, missing permission declarations weakens user/operator visibility and consent, making it easier for network-capable behavior to be installed or run without appropriate scrutiny.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation promotes one-click installation and startup behavior without clearly warning that the installer may add dependencies, make persistent system changes, or configure autorun. Hidden persistence and automatic software installation reduce informed consent and can surprise users with long-lived background behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill advertises persistent context but does not prominently warn that conversation history is automatically written to disk. Users may disclose sensitive personal or business information in chat, and silent local persistence increases privacy risk, especially on shared machines or systems with weak file protections.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documented configuration binds the bridge server to 0.0.0.0, exposing it on all network interfaces. For a desktop wallpaper/chat bridge intended for local use, this unnecessarily broadens attack surface and may allow other hosts on the network to reach chat, health, or state-clearing endpoints and potentially interact with the local AI gateway indirectly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The monitor forcibly kills and restarts processes automatically using taskkill and spawn with no user-facing notice, confirmation, or scoped ownership check. In a desktop wallpaper skill that runs persistently, this can disrupt unrelated Node.js workloads if the kill filter matches broadly, create surprise persistence, and reduce user control over background process behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The system prompt explicitly instructs the assistant to reply in Chinese, regardless of the user's preferences. This is a natural-language locale policy concern because the file does not provide any mechanism for the user to choose or opt into that language behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This second system prompt for streaming sessions also mandates Chinese replies for all users. Because no opt-in or locale selection is provided, it violates the requirement to avoid forcing a specific language by default.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

User messages and optional base64-encoded images are forwarded to the local gateway API, along with session identifiers, without any evidence here of explicit user consent or disclosure. In this skill's context, the wallpaper behaves like a persistent companion on the desktop, so users may reasonably assume private/local interaction and may not expect their text and images to be transmitted to another service.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comment at L452 states that expired sessions are cleaned up after 24 hours of inactivity, but the implementation at L453-L460 merely computes timestamps and logs the current number of active sessions. This is an active contradiction between documentation and behavior, especially relevant because the file also emphasizes long-running stability and persistence.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Conversation history is written to local disk in plaintext without any indication in this code that users are informed or that storage is minimized. In a desktop wallpaper/chat context, users may disclose sensitive personal content, and persistent storage increases the impact of local compromise, shared-machine access, backups, or forensic recovery.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file's visible UI strings, status text, welcome messages, errors, and achievement labels are all fixed in Chinese. This forces a specific language/locale experience without any apparent user choice, which matches the language-policy violation criteria.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The UI implements image upload handling and stores selected images as base64 for later transmission, but the skill description only advertises wallpaper chat features. This creates a transparency and consent problem because users may not reasonably expect image collection/processing from a wallpaper chat skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code captures pasted clipboard images and prepares them for upload without any prominent disclosure tied to clipboard handling. Clipboard ingestion is more sensitive than ordinary chat input because users can accidentally paste screenshots or other sensitive visual data into the wallpaper app.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code sends image data to the backend chat stream by embedding base64 image content in the request body, yet the manifest does not disclose image processing. Undisclosed transmission of user-provided images can expose screenshots, personal photos, or other sensitive content to backend components unexpectedly.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.install_untrusted_source

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
wallpaper-monitor.js:90

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
wallpaper-ui/LivelyProperties.json:5