Back to skill

Security audit

BlogStudio

Security checks for vulnerabilities and agentic risk

Overview

This is a plausible GitHub Pages blog editor, but it handles GitHub credentials and publishing authority in ways that could expose or misuse a user's token.

Review carefully before installing. Only run this with a narrowly scoped, revocable GitHub token for the intended repository, and avoid previewing untrusted repository content until token handling, renderer sanitization, IPC validation, and destructive-action controls are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
server.py:11
Finding

GitHub Access Token Exposed to Browser Content

Content
View full analysis

No GitHub token. Run: gh auth login

') return html = serve_html(token) self.send_response(200) self.send_header('Content-Type', 'text/html') self.send_header('Content-Length', len(html)) self.end_headers() self.wfile.write(html.encode()) ``` The legacy Python implementation has the equivalent behavior: ```python const TOKEN = "{token}"; ``` ```python class BlogStudioHandler(BaseHTTPRequestHandler): def do_GET(self): token = get_gh_token() if not token: self.send_response(401) self.send_header('Content-Type', 'text/html') self.end_headers() self.wfile.write(b'

GitHub token not found. Run: gh auth login

') return self.send_response(200) self.send_header('Content-Type', 'text/html') self.end_headers() self.wfile.write(make_html(token).encode()) ``` ### Technical Analysis The server obtains the authenticated user's GitHub token by executing `gh a ...[truncated 1991 chars]
Remediation
View remediation
` - `DELETE /api/posts/` 4. Validate repository paths against explicit content directories and accepted file extensions. 5. Generate a random per-launch session secret and require it on state-changing requests. 6. Validate `Origin` and `Host` headers and implement CSRF protection. 7. Return `Cache-Control: no-store` for all authenticated application responses. 8. Use a fine-grained GitHub token restricted to the required repository and Contents permission. 9. Add explicit route handling so arbitrary GET paths cannot retrieve application credentials. 10. Revoke and rotate any token that may already have been exposed through this design. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
server.py:216
Finding

Stored DOM Cross-Site Scripting in Markdown Preview and Repository Listings

Content
View full analysis
Start writing to see preview...'; return; } let html = md; html = html.replace(/```(\w*)\n([\s\S]*?)```/g, '
text
$2
'); html = html.replace(/`([^`]+)`/g, '$1'); html = html.replace(/^### (.+)$/gm, '

$1

'); html = html.replace(/^## (.+)$/gm, '

$1

'); html = html.replace(/^# (.+)$/gm, '

$1

'); html = html.replace(/\*\*([^*]+)\*\*/g, '$1'); html = html.replace(/\*([^*]+)\*/g, '$1'); html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); html = html.replace(/^> (.+)$/gm, '
$1
'); const paras = html.split(/\n\n+/); html = paras.map(p => p.startsWith('<') && p.endsWith('>') ? p : '

' + p.replace(/\n/g, '
') + '

').join(''); el.innerHTML = html; } ``` Repository-provided names and paths are also placed into HTML strings: ```javascript list.innerHTML = items.map(item => { const name = item.name; const dateMatch = name.match(/^(\d{4}-\d{2}-\d{2})/); const date = dateMatch ? dateMatch[1] : ''; const slug = name.replace(/\.(md|html)$/, '').replace(/^\d{4}-\d{2}-\d{2}-/, ''); const displayName = slug.replace(/-/g, ' ').replace(/^./, c => c.toUpperCase()); return '
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
electron/main.js:5
Finding

Undocumented Access to OpenClaw Secret Storage and Renderer Credential Disclosure

Content
View full analysis
{ win.webContents.send('init', { token: GITHUB_TOKEN, baseUrl: BASE_URL }); }); ``` The renderer explicitly receives and stores the credential: ```javascript let GITHUB_TOKEN = ''; let BASE_URL = ''; window.blogstudio.onInit((data) => { GITHUB_TOKEN = data.token; BASE_URL = data.baseUrl; console.log('BlogStudio initialized'); loadContent('posts'); }); ``` ### Technical Analysis The declared requirements document authentication through `gh auth login`, but the Electron implementation reads a fixed secret from `.openclaw/workspace/secrets/github-token.txt`. This crosses into an Agent workspace secret directory without that access being declared as necessary. The main process already performs GitHub requests through IPC handlers, so transmitting the token to the renderer serves no functional purpose. Electron renderers are a lower-trust boundary than the main process, especially where repository-controlled content is rendered. Any renderer compromise therefore gains access to a credential that should have remained isolated. This exceeds least privilege in two ways: 1. It reads a sensitive OpenClaw workspace file rather than relying on the documented authentication interface. 2. It sends the resulting credential into a renderer that does not need it. ### Attack Path 1. The victim launches the Electron application. 2. The main process derives the u ...[truncated 1060 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
electron/preload.js:3
Finding

Unrestricted Privileged Electron IPC Enables Repository Tampering and Unsafe URI Launching

Content
View full analysis
ipcRenderer.invoke('github-get', path), githubPut: (path, content, message) => ipcRenderer.invoke('github-put', path, content, message), githubDelete: (path, message) => ipcRenderer.invoke('github-delete', path, message), // Utility openExternal: (url) => ipcRenderer.invoke('open-external', url), showDialog: (options) => ipcRenderer.invoke('show-dialog', options), // Events onInit: (callback) => ipcRenderer.on('init', (event, data) => callback(data)) }); ``` The corresponding main-process handlers accept renderer-controlled arguments without validation: ```javascript ipcMain.handle('github-put', async (event, apiPath, content, message) => { const { default: fetch } = await import('node-fetch'); const res = await fetch(`${BASE_URL}/contents/${apiPath}`, { method: 'PUT', headers: { 'Authorization': `token ${GITHUB_TOKEN}`, 'Accept': 'application/vnd.github.v3+json', 'Content-Type': 'application/json' }, body: JSON.stringify({ message, content: Buffer.from(content).toString('base64'), branch: 'main' }) }); return res.json(); }); ``` ```javascript ipcMain.handle('github-delete', async (event, apiPath, message) => { const { default: fetch } = await import('node-fetch'); // First get the file SHA const getRes = await fetch(`${BASE_URL}/contents/${apiPath}`, { headers: { 'Authorization': `to ...[truncated 3138 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (60)

Lp1

High
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The code uses process.env to derive a secrets file path, which adds environment-derived capability beyond the declared permission model. In this skill, that matters because the environment is then used to locate and read a GitHub credential, effectively expanding access to sensitive data not disclosed in the manifest.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The main process reads a GitHub token and sends it to the renderer via win.webContents.send('init', { token: GITHUB_TOKEN, ... }). Renderer processes handle more complex, attack-prone content; exposing a long-lived token there greatly increases the chance of theft through XSS, compromised UI code, or unintended logging.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The delete handler performs authenticated remote deletion after resolving the file SHA, again without any visible confirmation or policy enforcement in this file. If the renderer is abused, an attacker could remove repository content or destroy pages with the user's token.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: brace-expansion==1.1.13 — 3 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro); CVE-2026-69152 (brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1)

High
Category
Supply Chain
Confidence
88% confidence
Finding

brace-expansion 1.1.13 is flagged with denial-of-service advisories and is present in the dependency tree. Even though it is under dev/build tooling, vulnerable parsing libraries can still be triggered during local builds, CI, or packaging workflows if attacker-controlled patterns are processed.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: @xmldom/xmldom==0.8.12 — 14 advisory(ies): CVE-2026-83608 (xmldom: DocType `name` Injection Bypasses requireWellFormed); CVE-2026-41673 (xmldom: Uncontrolled recursion in XML serialization leads to DoS); CVE-2026-83605 (xmldom: Attribute name injection via setAttribute() bypasses requireWellFormed) +11 more

High
Category
Supply Chain
Confidence
85% confidence
Finding

@xmldom/xmldom 0.8.12 has multiple XML parsing/serialization advisories and is used transitively by plist handling in build tooling. If untrusted XML/plist content is processed during packaging or metadata handling, this could lead to denial of service or malformed document handling issues.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: app-builder-lib==24.13.3 — 1 advisory(ies): CVE-2026-54672 (electron-updater: Uncontrolled search path elements within `AppImage` built by `)

High
Category
Supply Chain
Confidence
83% confidence
Finding

app-builder-lib 24.13.3 is flagged for an electron-updater-related vulnerability in produced AppImage artifacts. In an Electron project with packaging/deployment capability, insecure build tooling can directly affect shipped binaries and expose end users to update or search-path abuse.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: brace-expansion==2.0.3 — 3 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro); CVE-2026-69152 (brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-1)

High
Category
Supply Chain
Confidence
90% confidence
Finding

brace-expansion 2.0.3 is also present and carries DoS advisories. While likely limited to tooling paths, dependency-based resource exhaustion can still impact developer systems or CI infrastructure if malicious input reaches glob/matching operations.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: builder-util-runtime==9.2.4 — 1 advisory(ies): CVE-2026-54673 (electron-updater: Cross-origin redirect leaks `PRIVATE-TOKEN` and mixed-case `Au)

High
Category
Supply Chain
Confidence
90% confidence
Finding

builder-util-runtime 9.2.4 is reported vulnerable to token leakage across redirects in updater-related flows. For a blog CMS that deploys to GitHub Pages and likely handles repository credentials or update channels, any credential leakage in network/update code materially increases risk.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: electron==28.3.3 — 16 advisory(ies): CVE-2026-34776 (Electron: Out-of-bounds read in second-instance IPC on macOS and Linux); CVE-2026-70609 (Electron: DevTools JavaScript Injection via Unsanitized Dock State Parameter); CVE-2026-34767 (Electron: HTTP Response Header Injection in custom protocol handlers and webRequ) +13 more

High
Category
Supply Chain
Confidence
95% confidence
Finding

Electron 28.3.3 is flagged with numerous upstream security advisories, and this is a core runtime dependency rather than tooling metadata. Because the skill is an Electron-based CMS with file read/write and HTTP capabilities, Electron vulnerabilities can materially affect local file access, renderer/main process boundaries, custom protocols, and user compromise.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: extract-zip==2.0.1 — 2 advisory(ies): CVE-2026-19693 (extract-zip allows arbitrary file writes through symlink archive entries); CVE-2026-56876 (extract-zip unvalidated symlink path traversal)

High
Category
Supply Chain
Confidence
86% confidence
Finding

extract-zip 2.0.1 is flagged for symlink-based arbitrary write/path traversal issues. In this dependency tree it is used by Electron installation/build tooling, so the main exposure is during development or packaging rather than normal app runtime, but it could still be dangerous if malicious archives are handled.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
80% confidence
Finding

form-data 4.0.5 is flagged for CRLF injection in multipart field names and filenames. Here it is transitive in packaging/publishing tooling, so exploitability depends on whether attacker-controlled field names can influence outbound multipart requests, but the vulnerable version should still be treated as real technical debt.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: js-yaml==4.1.1 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
87% confidence
Finding

js-yaml 4.1.1 has multiple CPU exhaustion advisories around crafted YAML content. In this project it is used by build/config tooling, so the most likely impact is denial of service in development, CI, or packaging when processing attacker-influenced YAML files.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · index.html (reported line 178)May include surrounding context.

html
async function init() {
        // We need a backend to call gh auth token. Use the Python server as a proxy.
        // For truly standalone HTML, we open the Python app which injects the token.
        // But if opened directly, show instructions.
        const res = await fetch('/token').catch(() => null);
        if (res && res.ok) {
            const data = await res.json();

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · index.html (reported line 185)May include surrounding context.

html
token = data.token;
        } else {
            // Try GitHub REST with unauthenticated first request (will fail CORS)
            // Fallback: display instructions
            document.getElementById('contentList').innerHTML = `
                <div class="error-state">
                    <h3>BlogStudio needs a running server</h3>

Lp1

High
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill invokes a local external program via subprocess (gh auth token) to obtain credentials, which is effectively shell/process-execution capability beyond the declared permissions. Undeclared process execution increases the attack surface because a modified PATH, trojaned gh binary, or unexpected subprocess behavior could expose secrets or execute unintended code under the user's account.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The server injects the GitHub token directly into client-side JavaScript (const TOKEN = "...";), exposing a live credential to any script running in the page, browser extensions, devtools, local malware, or cross-site scripting payloads. Because the token is then used for authenticated GitHub API writes, compromise of the browser context can lead to repository takeover and potentially broader GitHub account abuse depending on token scope.

Content

No source excerpt is available for this finding.

Scope Creep

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code executes an external binary despite the declared permissions only covering file and HTTP access, creating a capability mismatch that can bypass user expectations and security review assumptions. In an agent skill, undeclared subprocess execution is more dangerous because it can access local tools, credentials, and state outside the stated trust boundary.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The server embeds the GitHub access token directly into the HTML/JavaScript sent to the browser, making the credential accessible to any script running in that page context. Because the page also renders unsanitized content into innerHTML, an injected script could steal the token and gain repository write access, turning a local editing app into a credential-exfiltration vector.

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 the skill can 'Publish straight to GitHub (main branch)', which is a user-data and system-integrity affecting action. The README describes the capability, but does not include any caution, confirmation expectation, or warning that publishing will directly change the live repository's main branch.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The README explicitly documents that the server injects a GitHub token obtained from gh auth token into the app, but provides no credential-handling warning or boundary explanation. In this skill context, the app has http.request, file.read, and file.write permissions and directly publishes to GitHub, so exposing or loosely handling a personal access token materially raises the risk of repository compromise or unintended credential leakage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill advertises one-click deploys and direct commits/pushes to GitHub without warning the user that repository content may be modified and published. In a CMS context with file.write and http.request permissions, this increases the chance of accidental publication, unintended repository changes, or pushing sensitive/draft content, especially if the UI does not require explicit confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file specifies safety-relevant actions including an immediate publish button and pushing changes to GitHub, which can directly alter production content. The description does not include any warning, confirmation, or caution about the impact of publishing or syncing remote changes.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill reads a GitHub token from a fixed path under the user's home directory, which is a sensitive credential source unrelated to normal blog content file access. Because the app can then use that token for authenticated repository operations, compromise of the app or renderer exposes account-level repository control.

Content

No source excerpt is available for this finding.

Scope Creep

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Accessing a credential file outside the stated CMS content scope violates least privilege and bypasses the manifest's apparent file.read/file.write intent. This makes the skill more dangerous because it silently expands from blog editing into secret harvesting from the user's home directory.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · electron/main.js (reported line 14)May include surrounding context.

js
const REPO_OWNER = 'TheSolAI';
const REPO_NAME = 'thesolai.github.io';
const BASE_URL = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}`;

function createWindow() {
    const win = new BrowserWindow({

Static analysis

Detected: suspicious.potential_exfiltration

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
electron/main.js:9