Agent Skills: JavaScript Security Skill

JavaScript security best practices and vulnerability prevention.

javascriptsecure-codingvulnerability-preventionbest-practicesxss
securityID: pluginagentmarketplace/custom-plugin-javascript/security

Skill Files

Browse the full folder contents for security.

Download Skill

Loading file tree…

skills/security/SKILL.md

Skill Metadata

Name
security
Description
JavaScript security best practices and vulnerability prevention.

JavaScript Security Skill

Quick Reference Card

XSS Prevention

// DANGEROUS - Never do this
element.innerHTML = userInput;

// SAFE - Use textContent
element.textContent = userInput;

// SAFE - Sanitize HTML
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);

// SAFE - Create elements
const div = document.createElement('div');
div.textContent = userInput;
parent.appendChild(div);

Input Validation

// Server-side validation is required
// Client-side is for UX only

function validateEmail(email) {
  const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return pattern.test(email);
}

function sanitizeInput(input) {
  return input
    .trim()
    .replace(/[<>]/g, ''); // Basic, use library for real apps
}

// Use schema validation
import { z } from 'zod';

const UserSchema = z.object({
  email: z.string().email(),
  age: z.number().min(0).max(150)
});

UserSchema.parse(userData); // Throws if invalid

Content Security Policy

<!-- In HTML head or HTTP header -->
<meta http-equiv="Content-Security-Policy"
  content="default-src 'self';
           script-src 'self' https://trusted.com;
           style-src 'self' 'unsafe-inline';">

Secure Storage

// NEVER store sensitive data in localStorage
// Use httpOnly cookies for tokens

// If you must use localStorage:
// - Don't store tokens
// - Don't store PII
// - Encrypt if necessary

// Secure cookie settings
document.cookie = 'token=abc; Secure; HttpOnly; SameSite=Strict';

CSRF Protection

// Include CSRF token in requests
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

fetch('/api/action', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
});

Dependency Security

# Audit dependencies
npm audit

# Fix vulnerabilities
npm audit fix

# Check specific package
npm audit --package-lock-only

# Use Snyk for deeper analysis
npx snyk test

Common Vulnerabilities

| Vulnerability | Prevention | |---------------|------------| | XSS | Use textContent, sanitize | | CSRF | Use tokens, SameSite cookies | | Injection | Parameterized queries | | Prototype pollution | Freeze prototypes | | Open redirect | Validate URLs |

Prototype Pollution Prevention

// Vulnerable
function merge(target, source) {
  for (const key in source) {
    target[key] = source[key]; // Can pollute __proto__
  }
}

// Safe
function safeMerge(target, source) {
  for (const key of Object.keys(source)) {
    if (key === '__proto__' || key === 'constructor') continue;
    target[key] = source[key];
  }
}

// Or use Object.assign / spread
const merged = { ...target, ...source };

Troubleshooting

Security Checklist

  • [ ] User input sanitized
  • [ ] HTTPS enforced
  • [ ] CSP headers set
  • [ ] Dependencies audited
  • [ ] Sensitive data encrypted
  • [ ] Auth tokens in httpOnly cookies
  • [ ] CSRF protection enabled
  • [ ] Error messages don't leak info

Debug Approach

// Log security events
window.addEventListener('securitypolicyviolation', (e) => {
  console.error('CSP violation:', e.blockedURI);
});

// Check for XSS vectors
const testInput = '<script>alert(1)</script>';
// If this executes, you have XSS

Production Patterns

JWT Handling

// Store in memory, not localStorage
let accessToken = null;

async function login(credentials) {
  const response = await fetch('/api/login', {
    method: 'POST',
    credentials: 'include', // For httpOnly refresh token
    body: JSON.stringify(credentials)
  });
  const { accessToken: token } = await response.json();
  accessToken = token; // Memory only
}

// Refresh before expiry
async function refreshToken() {
  const response = await fetch('/api/refresh', {
    credentials: 'include'
  });
  const { accessToken: token } = await response.json();
  accessToken = token;
}

URL Validation

function isSafeRedirect(url) {
  try {
    const parsed = new URL(url, window.location.origin);
    return parsed.origin === window.location.origin;
  } catch {
    return false;
  }
}

Related

  • Agent 08: Testing & Quality (detailed learning)
  • Skill: ecosystem: npm audit
  • Skill: patterns: Secure patterns
JavaScript Security Skill Skill | Agent Skills