T05 · Unauthorized Access and Privilege Escalation
- Location
server.mjs:141- Finding
Unauthenticated Cross-Origin Access to Privileged Local APIs
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a coherent avatar and presentation purpose, but its local server exposes sensitive unauthenticated APIs and unsafe command execution paths that need review before installation.
Only install this after reviewing the local-server risks. While running, another webpage or local process could potentially call its APIs, obtain NuwaAI tokens, alter stored configuration, send prompts through your OpenClaw gateway, or exploit the presentation parsing path. Use a test account/key, avoid confidential slide decks, and stop the server when finished.
server.mjs:141Unauthenticated Cross-Origin Access to Privileged Local APIs
server.mjs:420OS Command Injection Through Presentation Paths and Uploaded Filenames
server.mjs:46NuwaAI API Key Stored in Plaintext With Default File Permissions
public/index.html:996Microphone Capture and Third-Party Audio Transmission Start Automatically
public/index.html:983NuwaAI Access Token Exposed in WebSocket Query String
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
</head>
<body>
<!-- ─── Welcome Screen ─── -->
<div id="welcome-screen">
<div class="welcome-card">
<div style="text-align:right;margin-bottom:8px;">
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
</div>
</div>
<!-- ─── Trial Expired Overlay ─── -->
<div id="trial-overlay">
<div class="trial-card">
<div class="icon">⏰</div>
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
</div>
</div>
<!-- ─── Trial Expired Overlay ─── -->
<div id="trial-overlay">
<div class="trial-card">
<div class="icon">⏰</div>
When the WebSocket connects, the code automatically calls startRec() and begins microphone capture if permission has already been granted. This creates a covert audio-capture risk because reconnects or initial connection can activate recording without a fresh, explicit user action or a clear just-in-time disclosure.
Captured microphone PCM chunks are sent directly over the WebSocket to a remote NuwaAI service, but the UI does not clearly disclose at the point of recording that live speech is being transmitted off-device. In a voice/avatar skill, this is particularly sensitive because users may assume audio is only local or only used after explicit send actions.
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.
// Parse [PAGE:N] blocks
const pageRegex = /\[PAGE:(\d+)\]([\s\S]*?)(?=\[PAGE:\d+\]|$)/g;
let match;
while ((match = pageRegex.exec(reply)) !== null) {
const pageNum = parseInt(match[1], 10);
const script = match[2].trim();
const slide = data.slides.find(s => s.page === pageNum);
The server exposes an unauthenticated endpoint that mints and returns NuwaAI access tokens derived from a hard-coded demo API key. Combined with permissive CORS and local HTTP service exposure, any local webpage or process able to reach the port can harvest usable third-party tokens and abuse the demo account or consume its quota.
return;
}
// /api/demo/token — get access token
if (url.pathname === "/api/demo/token") {
try {
const resp = await fetch("https://api.nuwaai.com/web/apiKey/auth", {
The /api/token endpoint returns a live NuwaAI access token for the user's configured API key to any caller, with no authentication or authorization checks. Any local website, browser extension, or process that can reach this service can extract the token and impersonate the user against NuwaAI services.
}
}
// API: Get NuwaAI access token
if (req.url === "/api/token" && req.method === "GET") {
if (!nuwaConfig.apiKey) {
res.writeHead(200, { "Content-Type": "application/json" });
The skill instructs the agent to read a local presentation file, generate content, and then update presentation.json on disk without explicitly warning the user that local files will be modified or requiring confirmation before the write. This creates a real risk of unintended data modification, especially because the workflow targets user-supplied file paths and silently alters presentation artifacts as part of normal operation.
This code contains strings for microphone permission, recording state, and connection to an avatar service, indicating the skill captures live audio. However, there is no explicit warning in this file telling users that their voice may be sent to a remote service or processed externally; the text only reports permission/errors after the fact.
The setup flow sends the entered API key, avatar ID, and user ID to /api/config, but the surrounding UI only asks for the values and does not warn users that these credentials and identifiers will be transmitted to a backend service. For a safety-sensitive credential handling operation, there is no visible disclosure near the submission action.
The file includes multiple Chinese-only user-facing messages and, more importantly, the narration-generation prompt explicitly requires Chinese output. Because the skill does not offer user opt-in or a locale choice for these behaviors, it appears to enforce a specific language in violation of the language/locale policy.
Presentation contents are bundled into a prompt and transmitted to the OpenClaw gateway for script generation without explicit consent or warning. Because slides may contain confidential business or personal data, silent transmission to another service materially increases data exposure risk.
User-supplied NuwaAI credentials are persisted in plaintext to .nuwa-config.json without any access controls, encryption, or user warning. On a shared system or if local files are exposed through backups, malware, or other local compromise, these credentials can be recovered and abused.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// /api/demo/token — get access token
if (url.pathname === "/api/demo/token") {
try {
const resp = await fetch("https://api.nuwaai.com/web/apiKey/auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ secretKey: demo.apiKey }),
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// /api/demo/token — get access token
if (url.pathname === "/api/demo/token") {
try {
const resp = await fetch("https://api.nuwaai.com/web/apiKey/auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ secretKey: demo.apiKey }),
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// /api/demo/token — get access token
if (url.pathname === "/api/demo/token") {
try {
const resp = await fetch("https://api.nuwaai.com/web/apiKey/auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ secretKey: demo.apiKey }),
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
// /api/demo/token — get access token
if (url.pathname === "/api/demo/token") {
try {
const resp = await fetch("https://api.nuwaai.com/web/apiKey/auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ secretKey: demo.apiKey }),
The manifest frames the skill as an avatar/voice/presentation experience, yet the code exposes /api/chat and /api/chat/stream that forward arbitrary user messages to the OpenClaw chat completions endpoint. That is broader than slide narration or avatar control and effectively adds a generic chat gateway behavior not described in the manifest.
The upload endpoint writes the uploaded file to a temp path and invokes parse-presentation.py through execSync. While these actions may be functionally expected, the code lacks any confirmation, visible notice, or explanatory warning that uploaded content is being written locally and handed to an external parser process.
The manifest describes a skill for giving Claw a real-time avatar with voice/expressions and presenting slides, but it does not indicate that the server will invoke local subprocesses. The upload and parse flows call a Python script via child_process.execSync to process user-supplied presentation files, which is a materially broader capability than the stated avatar/presentation interface.
The language detection logic automatically selects Chinese for any zh-prefixed browser locale and English otherwise. This imposes a locale decision without explicit user choice, which matches the language/locale policy concern for natural-language behavior.
This code packages captured microphone PCM samples and posts them out of the AudioWorklet via MessagePort. There is no confirmation prompt, user-facing notice, or explanatory comment in this file indicating that raw audio data is being forwarded, which can affect privacy-sensitive user data handling.
Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal