Skip to content

Security-Hardened Intake Portal

Updated: February 21, 2026

Role: Sole implementer | 829 lines (HTML/JS/CSS) | 38 findings identified and remediated

For recruiters & hiring managers

What: Production security hardening project — identified and remediated 1 CRITICAL vulnerability plus 37 additional findings across security, accessibility, and compliance domains. Implemented XSS prevention, HMAC-SHA256 webhook authentication, RFC-compliant email validation, rate limiting, honeypot bot protection, and WCAG 2.1 AA accessibility compliance. Added CCPA/CPRA privacy disclosures with California-specific rights language.

Why this matters: Demonstrates application security discipline and compliance engineering depth — systematically identifying and remediating vulnerabilities across security, accessibility, privacy, and UX dimensions.

Impact: Eliminated CRITICAL localStorage injection vulnerability, achieved WCAG 2.1 AA compliance, implemented defense-in-depth security controls, and future-proofed privacy compliance for California market.

Skills: Application Security · Input Validation · XSS Prevention · HMAC Authentication · WCAG 2.1 AA · CCPA/CPRA · Rate Limiting · Bot Protection · Security Architecture · Compliance Engineering


Relationship to GIAP

This page documents the security engineering deep dive for the intake portal component of GIAP — Governance Intake Automation Platform. While GIAP covers the full platform architecture, this page focuses specifically on the portal security hardening methodology and implementation details.


Overview

The intake portal serves as the public-facing entry point for client engagement. A comprehensive security review identified 38 findings across security, accessibility, privacy, and UX domains, including a CRITICAL severity localStorage injection vulnerability. This case study documents the technical remediation.

Portal Specifications

Attribute Value
Version 2.2 (Production)
Live URL portal.aamcyber.work/demo
Codebase 829 lines (HTML/JS/CSS)
Security HMAC-SHA256 webhook auth, XSS sanitization, rate limiting, honeypot
Compliance WCAG 2.1 AA, GDPR, CCPA/CPRA, COPPA statement
Mobile Responsive, 48px touch targets, iOS zoom prevention

Review Summary

  • Total Findings: 38 across all domains
  • Critical Severity: 1 (localStorage injection)
  • High Severity: 7 (XSS risk, missing sanitization, accessibility gaps)
  • Medium/Low: 30 (UX improvements, compliance enhancements)
  • Remediation Rate: 100%

Security Findings

Finding SEC-01: localStorage Injection (CRITICAL)

The most significant vulnerability discovered was in the webhook endpoint configuration.

Before (Vulnerable):

// CRITICAL: Client-controlled URL injection
const webhookEndpoint = localStorage.getItem('webhookEndpoint')
  || 'https://n8n.aamcyber.com/webhook/giap-intake';

Vulnerability: An attacker could set localStorage.webhookEndpoint to any URL, causing the portal to exfiltrate form data to attacker-controlled servers.

After (Hardened):

// Hardcoded endpoint - no client-side override possible
const webhookEndpoint = 'https://n8n.aamcyber.com/webhook/giap-intake';

Rationale: The portal is single-purpose (one organization, one n8n instance). There's no legitimate use case for client-side endpoint configuration. Hardcoding eliminates the attack vector entirely.


Finding SEC-02: Missing Input Sanitization (HIGH)

Before: Raw form input passed directly to webhook payload, creating XSS risk if data is displayed elsewhere.

After:

function stripHtml(input) {
    return input.replace(/<[^>]*>/g, '')
               .replace(/[<>]/g, '');
}

// Applied to all text inputs before payload construction
const sanitizedName = stripHtml(formData.name);
const sanitizedOrg = stripHtml(formData.organization);

Finding SEC-03: Weak Email Validation (MEDIUM)

Before: Basic regex that allowed invalid email formats.

After (RFC 5322 Compliant):

function isValidEmail(email) {
    // RFC 5322 compliant pattern
    const pattern = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
    return pattern.test(email);
}

Finding SEC-04: No Rate Limiting (MEDIUM)

Implemented:

let lastSubmitTime = 0;
const SUBMIT_COOLDOWN = 5000; // 5 seconds

const now = Date.now();
if (now - lastSubmitTime < SUBMIT_COOLDOWN) {
    alert('Please wait a moment before submitting again.');
    return;
}
lastSubmitTime = now;

Note: Client-side rate limiting is defense-in-depth. Server-side rate limiting planned for GIAC API phase.


Finding SEC-05: No Bot Protection (MEDIUM)

Implemented (Honeypot Pattern):

<!-- Hidden from humans, visible to bots -->
<input type="text"
       name="website"
       id="honeypot"
       style="position:absolute;left:-9999px"
       tabindex="-1"
       autocomplete="off">

Server-side validation: If website field is populated, the submission is silently rejected (bots fill all visible fields).

Why honeypot over CAPTCHA:

  • No third-party dependencies (privacy-first)
  • Better UX (no user interaction required)
  • Effective against low-sophistication bots
  • Aligns with privacy-first brand positioning

HMAC Webhook Authentication

Beyond input validation, the portal implements cryptographic authentication for webhook requests.

Architecture

sequenceDiagram
    participant P as Portal
    participant N as n8n Webhook

    P->>P: Create payload JSON
    P->>P: Generate timestamp
    P->>P: HMAC-SHA256(timestamp + payload)
    P->>N: POST with headers
    Note over P,N: X-GIAP-Timestamp<br/>X-GIAP-Signature
    N->>N: Validate timestamp (5 min window)
    N->>N: Recompute HMAC
    N->>N: Compare signatures
    alt Valid
        N->>N: Process intake
    else Invalid
        N->>N: Reject (401)
    end

Figure: HMAC webhook authentication flow. Portal creates payload, generates timestamp, computes HMAC-SHA256 signature. n8n webhook validates 5-minute timestamp window, recomputes HMAC, and compares signatures before processing or rejecting.

Implementation

Portal (Client-side):

async function signPayload(payload) {
    const timestamp = Date.now().toString();
    const message = timestamp + JSON.stringify(payload);

    const encoder = new TextEncoder();
    const key = await crypto.subtle.importKey(
        'raw',
        encoder.encode(HMAC_SECRET),
        { name: 'HMAC', hash: 'SHA-256' },
        false,
        ['sign']
    );

    const signature = await crypto.subtle.sign(
        'HMAC',
        key,
        encoder.encode(message)
    );

    return {
        timestamp,
        signature: 'sha256=' + bufferToHex(signature)
    };
}

n8n (Server-side Validation):

// Code node in n8n workflow
const timestamp = $input.first().headers['x-giap-timestamp'];
const signature = $input.first().headers['x-giap-signature'];
const payload = JSON.stringify($input.first().json);

// Validate timestamp (5 minute window)
const now = Date.now();
if (Math.abs(now - parseInt(timestamp)) > 300000) {
    throw new Error('Request expired');
}

// Recompute and compare
const expectedSig = crypto
    .createHmac('sha256', $env.WEBHOOK_HMAC_SECRET)
    .update(timestamp + payload)
    .digest('hex');

if (signature !== 'sha256=' + expectedSig) {
    throw new Error('Invalid signature');
}

Security Properties

Property Implementation
Authenticity HMAC proves request originated from portal with shared secret
Integrity Payload tampering invalidates signature
Replay Prevention 5-minute timestamp window prevents replay attacks
Secret Rotation Secret stored in .env.local, rotatable without code changes

Accessibility Compliance (WCAG 2.1 AA)

Findings and Remediation

Finding Remediation
Missing skip navigation Added <a href="#main-content" class="skip-link">Skip to main content</a>
Checkbox touch targets too small Increased to 1.5em on mobile (48px minimum)
Required fields unclear Added legend: "Contact Information (all fields required)"
Missing autocomplete attributes Added autocomplete="name" and autocomplete="email"
SVG missing aria-hidden Added aria-hidden="true" to decorative SVG
External link warning Added <span class="sr-only">(opens in new tab)</span>
Alert not exposed to screen readers Added role="alert" aria-live="assertive"

Mobile Responsiveness

/* Touch targets - 48px minimum (WCAG 2.5.5) */
input[type="text"],
input[type="email"],
select,
textarea {
    min-height: 48px;
    font-size: 16px; /* Prevents iOS zoom */
}

/* Checkbox touch targets */
@media (max-width: 768px) {
    input[type="checkbox"] {
        width: 1.5em;
        height: 1.5em;
    }
}

/* Extra small devices (iPhone SE) */
@media (max-width: 375px) {
    .brand-mark { font-size: 1.8em; }
    h1 { font-size: 1.5em; }
}

Privacy Compliance (CCPA/CPRA)

Decision: Proactive CCPA Compliance

Although the business is Arizona-based (CCPA doesn't technically apply), we implemented California-specific disclosures:

Rationale:

  • Future-proofing for California clients (large market)
  • Demonstrates compliance maturity to HNWI clients
  • Minimal implementation cost
  • Aligns with privacy-first brand positioning

Implemented Disclosures

California Consumer Privacy Rights:

  • Right to Know (categories of personal information)
  • Right to Delete (request deletion within 45 days)
  • Right to Opt-Out (no sale of personal information)
  • Right to Correct (inaccurate information)
  • Right to Limit Use of Sensitive Personal Information
  • Right to Non-Discrimination

Additional Compliance:

  • COPPA statement (children's privacy)
  • Automated decision-making disclosure
  • Policy change notification process
  • Supervisory authority contact (EDPB, ICO)
  • International data transfer mechanisms (Standard Contractual Clauses)
  • Specific retention periods (2 years for inactive prospects)
  • Response timelines (7 days acknowledgment, 1 month response)

Brand Alignment

The review identified casual language that undermined the HNWI market positioning.

Copy Refinements

Original Revised Rationale
"We don't share a damned thing" "Your information stays with us. Period." Professional confidence without casualness
"security checkups" "security posture assessments" Industry-appropriate terminology
"Request Consultation" "Begin Conversation" Relationship-focused, not transactional
"We typically respond..." "Expect a personal response within 24 hours" Confident commitment

Trust Signals Added

  • "Confidential. No sales teams. No handoffs."
  • Explicit response time commitment
  • Privacy-first positioning throughout

Technical Decisions

Honeypot vs CAPTCHA

Factor Honeypot reCAPTCHA
Privacy No third-party data sharing Google tracking
UX Invisible to users Requires interaction
Effectiveness Good for low-sophistication bots Better for advanced bots
Dependencies None Google CDN dependency
Decision Selected Not aligned with privacy-first brand

Client-Side vs Server-Side Validation

Current: Client-side validation with HMAC signing.

Rationale:

  • Portal is pre-qualification only (not sensitive data)
  • n8n webhook validates payload structure
  • HMAC provides authenticity guarantee
  • Reduces infrastructure complexity during MVP

Future: Server-side validation mandatory when GIAC API is deployed.


What This Demonstrates

Security Engineering

  • Vulnerability identification — Systematic review across security domains
  • Defense-in-depth — Multiple layers (sanitization, rate limiting, HMAC, honeypot)
  • Secure defaults — Hardcoded endpoints, no localStorage dependencies
  • Cryptographic authentication — HMAC-SHA256 with replay prevention

Compliance Engineering

  • Accessibility — WCAG 2.1 AA with specific technical implementations
  • Privacy — CCPA/CPRA proactive compliance, COPPA statement
  • Data protection — GDPR consent mechanisms, retention policies

Application Security

  • Input validation — XSS prevention, RFC-compliant email validation
  • Bot protection — Privacy-respecting honeypot pattern
  • Rate limiting — Client-side throttling (defense-in-depth)

Evidence Artifacts

Artifact Description Status
Security review log Findings and remediation documentation ✅ Documented
HMAC implementation guide Setup and validation procedures ✅ Complete
WCAG compliance checklist Accessibility validation record ✅ Complete
Privacy policy (CCPA) California-specific disclosures ✅ Deployed
Security controls matrix SOC 2 / NIST mapping ✅ Documented


Contact LinkedIn