Back to skill

Security audit

Star Office UI

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real pixel-office dashboard, but public use would expose unauthenticated controls, reusable join keys, local memory snippets, and XSS-prone pages.

Use this only as a local or isolated demo until it is hardened. Before public exposure, add authentication for all control and memo endpoints, replace bundled join keys with deployment-specific secrets, disable or curate memory summaries, fix innerHTML rendering, align the documented port with the backend, and review/update dependencies.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
backend/app.py:414
Finding

Unauthenticated Administrative and State-Changing Endpoints

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
join-keys.json:2
Finding

Public Reusable Default Join Credentials Allow Unauthorized Enrollment

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
frontend/index.html:781
Finding

Stored Cross-Site Scripting Through Remote Agent Names

Content
View full analysis
暂无访客'; return; } list.innerHTML = visitors.map(agent => { const name = agent.name || '未命名访客'; const authStatus = agent.authStatus || 'pending'; const state = agent.state || 'idle'; ... const pendingActions = `交换skill` + `离开房间`; return `
${name}
${subtitle}
...[truncated 1808 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
frontend/index.html:501
Finding

Stored Cross-Site Scripting Through Memory Summary Content

Content
View full analysis
40: point = point[:37] + "..." ... return "\n".join(result).strip() ``` ```javascript async function loadMemo() { const memoDate = document.getElementById('memo-date'); const memoContent = document.getElementById('memo-content'); try { const response = await fetch('/yesterday-memo?t=' + Date.now(), { cache: 'no-store' }); const data = await response.json(); if (data.success && data.memo) { memoDate.textContent = data.date || ''; memoContent.innerHTML = data.memo.replace(/\n/g, '
'); } else { memoContent.innerHTML = '
暂无昨日日记
'; } } catch (e) { memoContent.innerHTML = '
加载失败
'; } } ``` ### Technical Analysis The server-side routine named `sanitize_content()` performs privacy-oriented pattern replacement, not HTML sanitization. I ...[truncated 1220 chars]
Remediation
View remediation
` elements. - If Markdown formatting is required, use a maintained parser configured to disable raw HTML and pass output through a strict allowlist sanitizer. - Treat memory files as untrusted content even when they are locally stored. - Keep privacy redaction separate from HTML output encoding; one does not replace the other. - Add a restrictive Content Security Policy as defense in depth. - Test memo rendering with tags, quoted attributes, SVG payloads, and encoded markup. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
office-agent-push.py:187
Finding

Free-Form Local Work Details Are Transmitted Externally Despite a Status-Only Privacy Claim

Content
View full analysis
"I will periodically send my work status > (idle/writing/researching/executing/syncing/error) to the office > dashboard for visual collaboration; it does not include specific > content/private information and can be stopped at any time." ... ## Notes - Only the status word and short description are pushed; no private content is pushed. ``` ```python def fetch_local_status(): candidate_files = [] if LOCAL_STATE_FILE: candidate_files.append(LOCAL_STATE_FILE) for fp in DEFAULT_STATE_CANDIDATES: if fp not in candidate_files: candidate_files.append(fp) for fp in candidate_files: try: if fp and os.path.exists(fp): with open(fp, "r", encoding="utf-8") as f: data = json.load(f) if not isinstance(data, dict): continue has_state = "state" in data has_detail = "detail" in data if (not has_state) and (not has_detail): continue state = normalize_state(data.get("state", "idle")) detail = data.get("detail", "") or "" state = map_detail_to_state(detail, fallback_state=state) return {"state": state, "detail": detail} except Exception: pass ``` ```python def do_push(local, status_data): import requests payload = { "agentId": local.get("agentId"), "joinKey": local.get("joinKey", JOIN_KEY), "state": status_data.get("state", "idle"), "detail": status_data.get("detail", ""), ...[truncated 1979 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:68
Finding

Public-Tunnel Instructions Target a Different Port Than the Backend Uses

Content
View full analysis
Open http://127.0.0.1:18791 to see the pixel office. ... ### Recommended method: Cloudflare Tunnel ```bash cloudflared tunnel --url http://127.0.0.1:18791 ``` ``` ```python if __name__ == "__main__": print("=" * 50) print("Star Office UI - Backend State Service") print("=" * 50) print(f"State file: {STATE_FILE}") print("Listening on: http://0.0.0.0:19500") print("=" * 50) app.run(host="0.0.0.0", port=19500, debug=False) ``` ### Technical Analysis The documented direct startup executes `backend/app.py`, which listens on port `19500`. The same instructions tell the Agent and owner to use port `18791`, including as the target of a public Cloudflare tunnel. The instructions do not verify that the service responding on `18791` is the intended Star Office backend. If another local service occupies that port, following the documented procedure could expose the unrelated service to the Internet. The backend also binds to all network interfaces even though tunneling only requires a loopback listener. ### Attack Path 1. Another local application is already listening on `127.0.0.1:18791`. 2. The user follows the Skill and starts `backend/app.py`, which actually listens on port `19500`. 3. The user follows the next instruction and runs a Cloudflare tunnel against port `18791`. 4. Cloudflare publishes the unrelated local application rather than Star Office. 5. Anyone with the generated public URL can access whatever service was unintentionally exposed. ### Impact Assessment The impact depends on the service present on port `18791`. Potential consequences include unintended public access to a local a ...[truncated 177 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
backend/app.py:742
Finding

Unauthenticated Memory Summary Endpoint Can Disclose Incompletely Redacted Agent Memory

Content
View full analysis
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (42)

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

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The script trusts LOCAL_STATUS_URL from an environment variable and sends a bearer token to whatever URL is provided. If that variable is manipulated, the script can be turned into an SSRF-style proxy or tricked into exfiltrating the local status token and polling arbitrary internal or external endpoints.

Content

Scanner excerpt · office-agent-push.py (reported line 145)May include surrounding context.

python
headers = {}
        if LOCAL_STATUS_TOKEN:
            headers["Authorization"] = f"Bearer {LOCAL_STATUS_TOKEN}"
        r = requests.get(LOCAL_STATUS_URL, headers=headers, timeout=5)
        if r.status_code == 200:
            data = r.json()
            state = normalize_state(data.get("state", "idle"))

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill description focuses on easy dashboard deployment, but the documented behavior includes reading local memory files, exposing their content through an endpoint, and mutating shared state through backend APIs. These extra behaviors materially expand the data-access and attack surface beyond what a user would reasonably expect from the description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README says the backend reads records from memory/*.md and applies only 'basic privacy sanitization' before display, but it does not warn that historical notes may still contain sensitive content. In this skill's context, surfacing prior work summaries through a UI or public endpoint can expose internal project details, personal data, or secrets that simple sanitization misses.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation advertises guest join and continuous status push capabilities without warning that invited agents can keep submitting data into the shared dashboard. That omission can cause users to trust this feature too broadly, increasing the risk of spoofed statuses, unwanted data injection, or unauthorized persistence if join keys or access controls are weak.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README explicitly encourages exposing the dashboard over Cloudflare Tunnel or another public domain, but it does not pair that guidance with clear warnings about authentication, authorization, or privacy risks. In the context of a dashboard that shows agent presence, status, and yesterday memo data, this can lead users to unintentionally publish operational or sensitive information to the internet.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs the agent to use shell, network, and filesystem operations but does not declare any explicit tool scope or permission boundaries. This increases the chance of overbroad execution, especially because the steps include cloning code, installing dependencies, launching a server, and exposing it publicly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill recommends exposing a locally hosted dashboard to the public internet via Cloudflare Tunnel and suggests alternative reverse proxies, but it does not prominently warn about privacy, authentication, or unintended data exposure. In this skill's context, that omission is more dangerous because the same document also references agent state updates, join keys, and yesterday-memo content that may be visible once exposed.

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 · backend/app.py (reported line 212)May include surrounding context.

python
def save_state(state: dict):
    """Save state to file"""
    with open(STATE_FILE, "w", encoding="utf-8") as f:
        json.dump(state, f, ensure_ascii=False, indent=2)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The /join-agent endpoint contradicts the intended approval flow by immediately setting authStatus to approved for any requester who presents a valid join key. This weakens access control: anyone who obtains or guesses a reusable key can register an agent and begin pushing state without human review, which is especially risky because the skill is designed for public/multi-agent remote access.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: flask==3.0.2 — 2 advisory(ies): CVE-2026-27205 (Flask session does not add `Vary: Cookie` header when accessed in some ways); CVE-2026-27205 (Flask is a web server gateway interface (WSGI) web application framework. In ver)

Medium
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is pinned to Flask 3.0.2, and the static analysis indicates it is affected by a published advisory related to missing Vary: Cookie handling for some session access patterns. In a web UI skill that exposes dashboards, mobile access, and public internet access, incorrect cache variation on cookie-bearing responses can lead to cache poisoning or cross-user content/session mix-ups under certain deployment configurations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file contains extensive hard-coded Chinese UI text, status labels, and messages, with no indication that language selection is configurable or that the feature is intentionally region-specific. That creates a locale policy concern because the skill effectively forces a specific language on all users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

Server-provided memo content is inserted with innerHTML after only replacing newlines, so any HTML in data.memo will be interpreted by the browser. If an attacker can influence the memo content, this becomes a straightforward stored or reflected XSS path that can execute script in users' sessions, alter the UI, or exfiltrate sensitive data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a one-click office UI for deployment, agent participation, visualization, mobile viewing, and public access. This file also implements a client-side function that POSTs to /set_state to change backend state, which goes beyond passive visualization and introduces a control capability not stated in the skill description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest promises a UI for deploying and visualizing a multi-agent office, implying display of real participating agents. The code unconditionally creates a fake agent_nika and periodically mutates its state with setInterval, meaning the UI can display fabricated agent presence and activity rather than only actual backend-driven status.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The memo content returned from /yesterday-memo is inserted with innerHTML after only replacing newlines with
, so any HTML delivered by the backend will execute or render in the page. In this dashboard context, that creates a straightforward stored or reflected XSS path if memo content can be influenced by an agent, operator, or compromised backend data source.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The guest agent list is built by interpolating untrusted fields like name, authStatus, state, and agentId into an HTML string assigned to list.innerHTML, including inside inline onclick handlers and data-* attributes. An attacker controlling those values could inject markup or JavaScript, leading to DOM XSS and potentially arbitrary actions in the dashboard such as approving, rejecting, or removing agents through the existing privileged endpoints.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.