Security Testing
Security testing should be automated and integrated into your development workflow. Find vulnerabilities before attackers do.
Static Application Security Testing (SAST)
# ESLint security plugin
npm install --save-dev eslint-plugin-security
# .eslintrc.js
module.exports = {
plugins: ['security'],
extends: ['plugin:security/recommended'],
rules: {
'security/detect-object-injection': 'error',
'security/detect-non-literal-regexp': 'error',
'security/detect-unsafe-regex': 'error',
'security/detect-buffer-noassert': 'error',
'security/detect-child-process': 'warn',
'security/detect-disable-mustache-escape': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-no-csrf-before-method-override': 'error',
'security/detect-possible-timing-attacks': 'error',
},
};
Semgrep
# Install Semgrep
pip install semgrep
# Run security rules
semgrep --config auto .
# Run specific rulesets
semgrep --config p/security-audit .
semgrep --config p/javascript .
# Custom rules
# semgrep.yml
rules:
- id: hardcoded-password
pattern: password = "..."
message: "Hardcoded password detected"
severity: ERROR
languages: [javascript, typescript]
Dynamic Application Security Testing (DAST)
# OWASP ZAP Docker
docker run -t owasp/zap2docker-stable zap-baseline.py -t https://your-app.com
# Generate HTML report
docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable \
zap-baseline.py -t https://your-app.com -r report.html
Dependency Scanning
# GitHub Actions workflow
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk to check vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'HIGH,CRITICAL'
Security Headers Testing
// Test security headers with Playwright
import { test, expect } from '@playwright/test';
test('security headers are set correctly', async ({ page }) => {
const response = await page.goto('https://your-app.com');
const headers = response.headers();
expect(headers['strict-transport-security']).toContain('max-age=');
expect(headers['x-frame-options']).toBe('DENY');
expect(headers['x-content-type-options']).toBe('nosniff');
expect(headers['content-security-policy']).toBeDefined();
expect(headers['referrer-policy']).toBeDefined();
});
test('no sensitive data in response', async ({ page }) => {
const response = await page.goto('https://your-app.com/api/user');
const body = await response.json();
// Ensure password is never returned
expect(body.password).toBeUndefined();
expect(body.passwordHash).toBeUndefined();
});
Penetration Testing Automation
// Custom security tests
describe('Security Tests', () => {
test('SQL injection protection', async () => {
const maliciousInputs = [
"'; DROP TABLE users; --",
"' OR '1'='1",
"1; SELECT * FROM users",
];
for (const input of maliciousInputs) {
const response = await fetch('/api/search', {
method: 'POST',
body: JSON.stringify({ query: input }),
});
// Should not return error indicating SQL execution
expect(response.status).not.toBe(500);
const data = await response.json();
expect(data.error).not.toContain('SQL');
}
});
test('XSS protection', async () => {
const xssPayloads = [
'<script>alert(1)</script>',
'<img src=x onerror=alert(1)>',
'javascript:alert(1)',
];
for (const payload of xssPayloads) {
const response = await fetch('/api/comment', {
method: 'POST',
body: JSON.stringify({ text: payload }),
});
const data = await response.json();
// Payload should be sanitized or rejected
expect(data.text).not.toContain('