Skip to content

[Security] : Task Viewer exposes unauthenticated APIs with permissive CORS, enabling remote file read, prompt injection, and config tampering #115

Description

@yuhanghuang

Summary

The Task Viewer component (tools/task-viewer/server.js) exposes 30+ REST API endpoints without any authentication, combined with a wildcard CORS policy (Access-Control-Allow-Origin: *). This allows any malicious website visited by a user running the Task Viewer to silently perform cross-origin requests against localhost:9998, leading to:

  • Arbitrary file read on the host machine
  • AI prompt template hijacking (persistent)
  • Global server configuration tampering
  • Full task data exfiltration (may contain credentials, keys, internal IPs)

Root Cause

1. Permissive CORS (server.js L457–463)

const server = http.createServer(async (req, res) => {
    // ...
    res.setHeader('Access-Control-Allow-Origin', '*');  // allows ANY origin
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    // No authentication check follows

Even though the server binds to 127.0.0.1 (localhost only), the browser's Same-Origin Policy is bypassed because the server explicitly allows all origins. A fetch() call from https://evil.com to http://localhost:9998/api/* will succeed.

2. No Authentication on Any Endpoint

All /api/* routes are publicly accessible. There is no token, session, or API key validation anywhere in the request handling chain.

3. Unsanitized File Path in /api/add-project (server.js L520–530)

filePath = formData.get('filePath'); // user-controlled, no validation
// ...
const project = await addProject(name, filePath, projectRoot); // stored as-is

The filePath parameter accepts arbitrary absolute paths. Subsequent GET /api/tasks/{id} calls read the file via fs.readFile(project.path, 'utf8') (L720) and return its contents. For non-JSON files, the parse error message may still leak partial content.

4. Unprotected Template Write (server.js L950–955)

} else if (req.method === 'PUT') {
    const { content } = JSON.parse(body); // attacker-controlled
    const success = await saveCustomTemplate(functionName, content); // direct overwrite

Any origin can overwrite system prompt templates (e.g., executeTask), permanently altering the AI Agent's behavior.

Reproduction progress

Save the following as poc.html and open it in a browser while the Task Viewer is running:
https://drive.google.com/file/d/1udfTlueFoKAMjx_Fr85MAL1b0x4nUOoI/view?usp=sharing

Attack scenario: User runs Task Viewer locally → visits a compromised/malicious website → attacker's JavaScript silently calls localhost:9998 APIs → credentials stolen, AI agent hijacked.

Image Image Image Image

poc.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions