Back to skill

Security audit

Bear Blog Publisher

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly does what it claims, but it handles blog-account passwords and public publishing in ways users should review carefully before installing.

Review this before installing if you plan to give it real Bear Blog credentials. Prefer isolated credentials, avoid passing passwords in chat or command-line arguments, do not store passwords in plaintext config unless you accept that risk, and require a manual confirmation before publishing. Treat AI generation as sending prompts to OpenAI or Kimi, and avoid using the diagram feature with untrusted text until the HTML escaping, temp-file handling, and browser sandboxing are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/publish.py:367
Finding

Unescaped HTML Injection in Unsandboxed Browser with Unsafe Temporary Files

Content
View full analysis
{title}
{''.join(f'
{comp}
' for comp in components)}
""" html_path = '/tmp/diagram.html' with open(html_path, 'w') as f: f.write(html_content) with sync_playwright() as p: browser = p.chromium.launch(headless=True, args=['--no-sandbox']) page = browser.new_page(viewport={'width': 1100, 'height': 400}) page.goto(f'file://{html_path}') page.wait_for_timeout(500) screenshot_path = '/tmp/diagram.png' page.screenshot(path=screenshot_path, full_page=True) browser.close() ``` ### Technical Analysis The diagram title and component values are interpolated directly into an HTML document without HTML escaping or validation. Because this document is subsequently loaded by Chromium, a caller capable of controlling `title` or `components` can inject active HTML, including scripts, event handlers, resource-loading elements, or malformed markup. Chromium is explicitly launched with `--no-sandbox`. This does not by itself grant injected JavaScript operating-system access, but it removes an important containment layer and increases the impact of any browser vulnerability or renderer compromise. The generated HTML and PNG also use globally predictable paths in the shared `/tmp` directory. Opening `/tmp/diagram.html` with the default Python write mode follows symbolic links. A local attacker may therefore pre-create that path as a symlink to another file writable by the publisher process. Similar race and content-integrity concerns affect the predictable screenshot path. ### Attack Path 1. An attacker supplies a diagr ...[truncated 1431 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/publish.py:398
Finding

Bear Blog Password Exposed Through Command-Line Arguments

Content
View full analysis
[email] [password]") print("") print("Authentication methods (in priority order):") print(" 1. Command line arguments: email password") print(" 2. Environment variables: BEAR_BLOG_EMAIL, BEAR_BLOG_PASSWORD") print(" 3. Config file: ~/.openclaw/openclaw.json") print("") print("For AI content generation, set OPENAI_API_KEY or KIMI_API_KEY") sys.exit(1) title = sys.argv[1] with open(sys.argv[2], 'r') as f: content = f.read() email = sys.argv[3] if len(sys.argv) > 3 else None password = sys.argv[4] if len(sys.argv) > 4 else None ``` ### Technical Analysis The CLI explicitly supports passing the Bear Blog password as a positional command-line argument. Process arguments are commonly visible through process inspection facilities, monitoring software, audit logs, job schedulers, diagnostic output, and command history. Although exposure details depend on operating-system policy, command-line arguments are not an appropriate secret transport mechanism. The risk is unnecessary because the project already supports environment variables and configuration-based credential resolution. ### Attack Path 1. A user follows the displayed CLI instructions and invokes the script with a plaintext password. 2. The shell may save the entire command in history. 3. While the process is running, a local user or monitoring process with sufficient visibility reads the command line from process-management tools or operating-system process metadata. 4. Alternatively, CI logs, wrappers, schedulers, or diagnostic systems record the complete invocation. 5. The observer recovers the Bear Blog email and password and uses them to authenticate ...[truncated 522 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
package.json:22
Finding

Unpinned Python and Chromium Dependencies Create Mutable Supply-Chain Exposure

Content
View full analysis
Remediation
View remediation
--hash=sha256: playwright== --hash=sha256: ``` 3. Pin the Playwright version and its corresponding Chromium revision as a reviewed pair. 4. Install packages only from trusted, explicitly configured indexes. 5. Verify downloaded browser artifacts using publisher signatures or cryptographic hashes where supported. 6. Run dependency installation as an unprivileged user and isolate installation from production secrets. 7. Use automated dependency scanning, but review and deliberately update the lock data rather than accepting mutable versions at installation time. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
README.md:19
Finding

Documentation Incorrectly Claims Credentials Are Never Persisted

Content
View full analysis
Environment > Config ``` ### Technical Analysis The README instructs users to persist a plaintext Bear Blog password in `~/.openclaw/openclaw.json`, but later states that credentials only exist in memory and are not persistently stored. These claims are contradictory. Restrictive file permissions reduce exposure to other local users but do not make the secret nonpersistent. The password remains accessible to the account owner, privileged processes, backups, malware operating as that user, and any software allowed to read the configuration file. `SKILL.md` separately acknowledges the plaintext configuration option, but the conflicting README statement can still cause users to make decisions based on an inaccurate security guarantee. ### Attack Path 1. A user relies on the claim that credentials are never persistently stored. 2. The user selects the configuration-file authentication method. 3. The Bear Blog password is written in plaintext to `~/.openclaw/openclaw.json`. 4. A process running as the same user, a privileged administrator, compromised backup system, or malware with access to the home directory reads the file. 5. The recovered creden ...[truncated 515 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (23)

Tainted flow: 'api_key' from os.environ.get (line 133, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/publish.py (reported line 115)May include surrounding context.

python
if not api_key:
            raise ValueError("OPENAI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

Tainted flow: 'api_key' from os.environ.get (line 133, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/publish.py (reported line 137)May include surrounding context.

python
if not api_key:
            raise ValueError("KIMI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.moonshot.cn/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README promotes publishing user-provided and AI-generated content to Bear Blog but does not clearly warn that submitted content is sent to an external platform and, once published, becomes publicly accessible. In a skill that may process pasted private notes, drafts, or sensitive AI-generated material, this omission can lead to unintended data disclosure by users who do not realize the action is externally transmitted and public.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 36)May include surrounding context.

Set secure permissions:

bash
chmod 600 ~/.openclaw/openclaw.json

Method 2: Environment Variables

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · examples/blog-draft.md (reported line 71)May include surrounding context.

Set secure permissions:

bash
chmod 600 ~/.openclaw/openclaw.json

Method 2: Environment Variables

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The AI content generation section instructs users to provide OpenAI or Kimi API keys and generate content, but it does not warn that prompts, source text, or related inputs may be transmitted to third-party AI providers. If users supply sensitive drafts or proprietary material, this omission increases the risk of unintentional exposure to external services beyond Bear Blog itself.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documentation describes capabilities that require access to environment variables, files, network, and shell-like execution, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an over-privileged and ambiguous execution model where a host agent may grant broader access than necessary, increasing the risk of credential exposure, arbitrary file access, or unintended outbound requests.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · examples/blog-draft.md (reported line 9)May include surrounding context.

md
## Introduction

[Bear Blog](https://bearblog.dev/) is a privacy-focused, no-tracking blogging platform that lets you write without distractions. But what if you want to automate your publishing workflow? 

Enter **Bear Blog Publisher** — an OpenClaw skill that enables automatic blog publishing with optional AI content generation and diagram creation. In this guide, I'll walk you through how to set it up and share my real-world experience integrating it with Feishu (Lark) assistant.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document explicitly describes a workflow where a chat assistant asks users to provide Bear Blog email and password, but it does not warn that chat platforms, bot logs, middleware, or operators may retain or expose those credentials. In the context of a publishing skill integrated with Feishu/OpenClaw, encouraging password submission over chat materially increases the risk of credential theft, accidental logging, and cross-system compromise.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The activation condition and examples are broad enough that the skill may be selected for generic requests to write or create blog content, not just explicit requests to publish to Bear Blog. In this skill's context, that matters because the skill has publishing capability plus access to optional credentials and API keys, so over-broad routing could cause unintended external posting or credential use when the user only wanted drafting assistance.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest describes a blog publishing skill that supports user-provided and AI-generated content, but it does not state that the skill will inspect process environment variables or local configuration files for secrets. Reading local secret stores is an additional credential-access capability beyond the user-facing publishing purpose and should be explicitly declared if intended.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/publish.py (reported line 67)May include surrounding context.

python
# Check file permissions (should be 600)
                    file_stat = config_path.stat()
                    if file_stat.st_mode & stat.S_IRWXG or file_stat.st_mode & stat.S_IRWXO:
                        print("Warning: Config file is readable by others. Run: chmod 600 ~/.openclaw/openclaw.json")
                    return config_email, config_password
            except (json.JSONDecodeError, KeyError):
                pass

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · scripts/publish.py (reported line 80)May include surrounding context.

python
Generate blog content using AI.
        
        Args:
            topic: What to write about
            provider: LLM provider ('openai' or 'kimi')
            tone: Writing style (professional, casual, technical)
            length: short, medium, or long

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · scripts/publish.py (reported line 115)May include surrounding context.

python
if not api_key:
            raise ValueError("OPENAI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · scripts/publish.py (reported line 137)May include surrounding context.

python
if not api_key:
            raise ValueError("OPENAI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/publish.py (reported line 115)May include surrounding context.

python
if not api_key:
            raise ValueError("OPENAI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

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 · scripts/publish.py (reported line 116)May include surrounding context.

python
raise ValueError("OPENAI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/publish.py (reported line 137)May include surrounding context.

python
if not api_key:
            raise ValueError("KIMI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.moonshot.cn/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

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 · scripts/publish.py (reported line 138)May include surrounding context.

python
raise ValueError("KIMI_API_KEY environment variable not set")
        
        response = requests.post(
            "https://api.moonshot.cn/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The upload_image method reads a local file and transmits it to Bear Blog over HTTP after authenticating, but there is no visible warning, confirmation, or user-facing disclosure inside this method about sending file contents off-device. The docstring describes the functional outcome but does not clearly warn about the privacy-impacting network transfer of a local file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The publish flow performs authenticated requests to Bear Blog using stored credentials and submits content for publication, but the method has no confirmation prompt or explicit user-facing disclosure before the irreversible publish action. Although the docstring says 'Publish a blog post,' it does not clearly warn that executing this function will immediately log in and publish content to a live remote service.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest says the skill supports auto-generated diagrams, but the code implements this by spawning a headless Chromium instance via Playwright with --no-sandbox to render and screenshot HTML. Launching a browser process is a substantially broader capability than simple blog publishing and should be explicitly scoped because it introduces execution behavior unrelated to core post submission.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The generate_content flow sends the user-supplied topic and constructed prompt to either OpenAI or Kimi via external API calls, but there is no explicit user-facing warning that the input will be transmitted to third-party services. The docstrings identify the providers but do not clearly disclose the privacy implication of sharing prompt content externally.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/publish.py:33

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:175