Skip to content

[Backend] Add Authentication to GET /api/tasks/:id and DELETE /api/tasks/:id Endpoints #161

Description

@devJaja

🎯 Objective

Add authentication and ownership verification to GET /api/tasks/:id and DELETE /api/tasks/:id to prevent information disclosure and unauthorized task cancellation.


📁 Files to Modify

Action File Path Description
Modify backend/src/api/app.ts Add ownership checks to task endpoints
Modify backend/src/api/docs/openapi.ts Document auth requirements

📁 Files to Create/Modify (Tests)

Action File Path Description
Modify backend/tests/tasks.test.ts Add tests for unauthorized access

🔍 Current Vulnerable Code (app.ts)

// VULNERABLE — No auth, returns full task details to anyone
app.get('/api/tasks/:id', async (req, res) => {
  const task = taskStore.getTask(req.params.id);
  // Returns: prompt, DAG, results, walletPublicKey — all exposed
  res.json(task);
});

// VULNERABLE — No ownership check, anyone can cancel any task
app.delete('/api/tasks/:id', async (req, res) => {
  const task = taskStore.getTask(req.params.id);
  if (task.status === 'queued') {
    taskStore.updateTaskStatus(task.id, 'cancelled');
    res.json({ status: 'cancelled' });
  }
});

💥 Impact

  • Any user can read any other user's task prompts and results (information disclosure)
  • Any user can cancel any other user's queued tasks (denial of service)
  • Sensitive data in prompts (business plans, code, etc.) is exposed

✅ Expected Fix

GET /api/tasks/:id

app.get('/api/tasks/:id', async (req, res) => {
  const task = taskStore.getTask(req.params.id);
  if (!task) {
    return res.status(404).json({ error: 'Task not found' });
  }

  const requesterKey = req.headers['walletpublickey'] as string;

  // If requester is not the owner, redact sensitive fields
  if (requesterKey && requesterKey !== task.walletPublicKey) {
    return res.status(403).json({ error: 'Access denied' });
  }

  res.json(task);
});

DELETE /api/tasks/:id

app.delete('/api/tasks/:id', async (req, res) => {
  const task = taskStore.getTask(req.params.id);
  if (!task) {
    return res.status(404).json({ error: 'Task not found' });
  }

  const requesterKey = req.headers['walletpublickey'] as string;
  if (!requesterKey || requesterKey !== task.walletPublicKey) {
    return res.status(403).json({ error: 'Not authorized to cancel this task' });
  }

  if (task.status !== 'queued') {
    return res.status(409).json({ error: `Cannot cancel task in '${task.status}' status` });
  }

  taskStore.updateTaskStatus(task.id, 'cancelled');
  res.json({ status: 'cancelled' });
});

📁 Reference Files

File Path Purpose
backend/src/api/app.ts (line ~303) GET /api/tasks/:id
backend/src/api/app.ts (line ~345) DELETE /api/tasks/:id
backend/src/coordinator/taskStore.ts Task storage interface
backend/src/api/middleware/auth.ts Existing auth middleware pattern

✅ Acceptance Criteria

  • Add ownership check to GET /api/tasks/:id
  • Add ownership verification to DELETE /api/tasks/:id
  • Return HTTP 403 for unauthorized access attempts
  • Return HTTP 404 for nonexistent tasks
  • Only allow cancellation of queued tasks (not running or completed)
  • Update OpenAPI spec with auth requirement
  • Add test: access task with wrong wallet key → 403
  • Add test: cancel task with wrong wallet key → 403
  • Add test: access/cancel own task → success

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions