Back to skill

Security audit

Materials Workbench

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent AI materials workbench, but it exposes credential-backed local services and uploads images to third parties with incomplete scoping and disclosure.

Review before installing. Only run this on a trusted machine, avoid exposing port 3001 beyond localhost, do not use sensitive images unless you accept upload to PICUI and the configured AI provider, and prefer packaging audited dependencies inside the artifact or pinning reviewed registry versions before use.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server/src/index.ts:18
Finding

Unauthenticated API permits unauthorized use of server-side AI and image-hosting credentials

Content
View full analysis
{ console.log(`Server running at http://localhost:${port}`); }); ``` ```ts router.post("/", async (req: Request, res: Response) => { const apiKey = openai.apiKey; if (!apiKey) { res.status(500).json({ error: "OPENAI_API_KEY is not set" }); return; } const body = req.body as ChatRequestBody; const messages = body?.messages; if (!Array.isArray(messages)) { res.status(400).json({ error: "messages array is required" }); return; } // Upload base64/data URL images to PICUI on the server; keep http(s) URLs as-is const normalized: ChatMessage[] = await Promise.all( messages.map(async (m) => { let image = m.image; if (image && needsPicuiUpload(image)) { try { image = await uploadDataUrlToPicui(image); ``` ```ts await chat(apiKey, normalized, currentRenderData, sendEvent, { baseURL: openai.baseURL, model: openai.model, getMaxTokens: (agent) => getMaxTokens(agent), }); ``` ### Technical Analysis The `/api/chat` route performs privileged operations using the server owner's `OPENAI_API_KEY` and, when images are supplied, `PICUI_TOKEN`. The route has no authentication or authorization check. The application also enables permissive CORS through `cors()` with default settings and does not explicitly bind the listener to the loopback interface. Consequently, any party capable of reaching port 3001 can cause the server to make owner-funded AI requests and PICUI uploads. Browser-based requests can also originate from arbitrary websites because the ...[truncated 1796 chars]
Remediation
View remediation
{ console.log(`Server running at http://${host}:${port}`); }); ``` 2. Replace unrestricted CORS with an explicit allowlist, such as `http://localhost:5173`, and reject unrecognized origins. 3. Require authentication for every privileged endpoint. For local use, generate a random per-session bearer token and require the client to provide it. 4. Add per-client and global rate limits, concurrency limits, request timeouts, and maximum SSE stream durations. 5. Limit the number and length of messages and validate the complete request schema at runtime. 6. Enforce strict encoded and decoded image-size limits before allocating buffers or uploading content. 7. Configure finite model-output token limits rather than allowing an undefined maximum. 8. Add spending limits and quota alerts at both OpenAI and PICUI. 9. Avoid exposing the development service through public network interfaces, reverse proxies, or tunnels unless production-grade access controls are enabled. ]]>

other

Warning
Location
server/src/picui.ts:27
Finding

Attached images are automatically disclosed to public third-party hosting

Content
View full analysis
{ let image = m.image; if (image && needsPicuiUpload(image)) { try { image = await uploadDataUrlToPicui(image); } catch (err) { const msg = err instanceof Error ? err.message : "Image upload failed"; throw new Error(msg); } } return { role: m.role, ``` ```ts export async function uploadDataUrlToPicui(dataUrl: string): Promise { const token = picui.token; if (!token) { throw new Error("PICUI_TOKEN is not set. Add it to server/.env from https://picui.cn"); } const parsed = parseImageData(dataUrl); if (!parsed) { throw new Error("Invalid image data: expected data URL (data:mime;base64,...) or base64 string"); } const { buffer, mime } = parsed; const formData = new FormData(); const blob = new Blob([new Uint8Array(buffer)], { type: mime }); formData.append("file", blob, "image.png"); const picuiRes = await fetch(`${picui.baseURL}/upload`, { method: "POST", headers: { Authorization: `Bearer ${token}`, Accept: "application/json", }, body: formData, }); const json = (await picuiRes.json()) as { status?: boolean; message?: string; data?: { links?: { url?: string } }; }; if (!picuiRes.ok) { throw new Error(json.message ?? `PICUI upload failed: ${picuiRes.statusText}`); } const url = json.data?.links?.url; if (!url) { throw new Error("PICUI did not return image URL"); } return url; } ``` ### Technical Analysis Every image that is not already an HTTP or HTTPS URL is automatically decoded a ...[truncated 2617 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
server/package.json:15
Finding

Core runtime dependencies resolve to unaudited code outside the project boundary

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (39)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve .env relative to server directory (one level up from src)
const envPath = resolve(__dirname, "..", ".env");
const result = dotenv.config({ path: envPath });
if (result.error) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · server/src/index.ts (reported line 8)May include surrounding context.

ts
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve .env relative to server directory (one level up from src)
const envPath = resolve(__dirname, "..", ".env");
const result = dotenv.config({ path: envPath });
if (result.error) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · server/src/index.ts (reported line 12)May include surrounding context.

ts
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve .env relative to server directory (one level up from src)
const envPath = resolve(__dirname, "..", ".env");
const result = dotenv.config({ path: envPath });
if (result.error) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · server/src/picui.ts (reported line 31)May include surrounding context.

ts
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve .env relative to server directory (one level up from src)
const envPath = resolve(__dirname, "..", ".env");
const result = dotenv.config({ path: envPath });
if (result.error) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · server/src/picui.ts (reported line 80)May include surrounding context.

ts
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve .env relative to server directory (one level up from src)
const envPath = resolve(__dirname, "..", ".env");
const result = dotenv.config({ path: envPath });
if (result.error) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · server/src/index.ts (reported line 9)May include surrounding context.

ts
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Resolve .env relative to server directory (one level up from src)
const envPath = resolve(__dirname, "..", ".env");
const result = dotenv.config({ path: envPath });
if (result.error) {
  console.warn(`Warning: Could not load .env from ${envPath}:`, result.error.message);

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 · README.md (reported line 21)May include surrounding context.

bash
   # Edit server/.env and set:
   # OPENAI_API_KEY=your-key
   # OPENAI_BASE_URL=https://api.hunyuan.cloud.tencent.com/v1  # Optional, for custom endpoints
   # OPENAI_MODEL=hunyuan-lite  # Optional, defaults to gpt-4o
   # PICUI_TOKEN=your-token     # Optional, for image uploads. Get from https://picui.cn personal center

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill declares environment and network capabilities via required environment variables and a server/client application flow, but it does not explicitly constrain tool scope with permissions or allowed-tools. That makes the runtime trust boundary ambiguous and can permit broader-than-necessary access to secrets or network operations, especially since the workflow uses an OpenAI API key and starts local services that may make outbound requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code transmits user-entered text, optional image data, and the current render state via postChatStream, which is a network operation affecting user data and privacy. In this file there is no visible warning, confirmation, or explanatory text near send/attach actions that tells users this data will be uploaded to a backend service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code automatically uploads image content received by the server to a third-party public hosting service, which can expose sensitive or proprietary images without explicit user awareness or consent. In the context of a materials editor and chat/image workflow, users may reasonably expect local processing, so silent external transmission creates a privacy and data-handling risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

Rendered image buffers are sent to an external PICUI endpoint and turned into public URLs with no indication in this code of authorization, user notice, or sensitivity checks. If the rendered output contains confidential schema data, design artifacts, or embedded secrets, this can result in unintended public disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This route automatically uploads user-supplied data URL/base64 images to an external PICUI service before processing, with no evidence in this code path of user consent, disclosure, allowlisting, or content governance. That creates a privacy and data-handling risk because users may submit sensitive images expecting local processing, while the server silently transfers them to a third party.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The document declares lang="en", which sets the interface language to English. Under the policy criteria, forcing a specific language without offering user choice or documenting a justified regional constraint is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 12)May include surrounding context.

json
"preview": "vite preview"
  },
  "dependencies": {
    "declare-render": "^1.1.5",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · server/package.json (reported line 14)May include surrounding context.

json
"preview": "vite preview"
  },
  "dependencies": {
    "declare-render": "^1.1.5",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 13)May include surrounding context.

json
},
  "dependencies": {
    "declare-render": "^1.1.5",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {

Unverifiable Dependency: react has 2 known advisory(ies) (CVE-2013-7035 (Cross-Site Scripting in react); GHSA-hg79-j56m-fxgv (Cross-Site Scripting in react)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 14)May include surrounding context.

json
"dependencies": {
    "declare-render": "^1.1.5",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.3.12",

Unverifiable Dependency: react-dom has 1 known advisory(ies) (CVE-2018-6341 (Cross-Site Scripting in react-dom)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 17)May include surrounding context.

json
"react-dom": "^18.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "typescript": "^5.3.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 18)May include surrounding context.

json
},
  "devDependencies": {
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "typescript": "^5.3.0",
    "vite": "^5.4.10"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 19)May include surrounding context.

json
"devDependencies": {
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "typescript": "^5.3.0",
    "vite": "^5.4.10"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 20)May include surrounding context.

json
"@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "typescript": "^5.3.0",
    "vite": "^5.4.10"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · client/package.json (reported line 21)May include surrounding context.

json
"@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "typescript": "^5.3.0",
    "vite": "^5.4.10"
  }
}

Unverifiable Dependency: vite has 16 known advisory(ies) (CVE-2023-34092 (Vite Server Options (server.fs.deny) can be bypassed using double forward-slash ); CVE-2025-32395 (Vite has an `server.fs.deny` bypass with an invalid `request-target`); CVE-2025-31125 (Vite has a `server.fs.deny` bypassed for `inline` and `raw` with `?import` query) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.