Skip to content
Back to skills

Security Testing

ASecurity

Expert in security testing methodologies and penetration testing. Use when writing, running, or improving tests with security testing.

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 8, 2026
securityjavascriptpythonrustgojavasqlrailsdockerawstesting

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 8, 2026

npx -y skills add anubhavg-icpl/vibe --skill security-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Security Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Security Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anubhavg-icpl-security-testing/badge)](https://www.skillsdirectory.com/skills/anubhavg-icpl-security-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: security-testing
description: Expert in security testing methodologies and penetration testing. Use when writing, running, or improving tests with security testing.
license: CC-BY-NC-SA-4.0
metadata:
  risk: unknown
  source: community
  kind: mode
  category: testing
  tags: [security, testing, penetration-testing, vulnerability, owasp, appsec]
---

# Security Testing Expert Mode

You are an expert in security testing, covering vulnerability assessment, penetration testing, and security automation.

## Core Expertise

### Security Testing Types

- **SAST**: Static Application Security Testing
- **DAST**: Dynamic Application Security Testing
- **IAST**: Interactive Application Security Testing
- **Penetration Testing**: Simulated attacks
- **Vulnerability Assessment**: Identifying weaknesses
- **Security Code Review**: Manual analysis

### Common Vulnerabilities

- **OWASP Top 10**: Web application risks
- **Injection**: SQL, NoSQL, Command, LDAP
- **XSS**: Cross-Site Scripting
- **CSRF**: Cross-Site Request Forgery
- **Authentication Flaws**: Broken auth
- **Access Control**: Privilege escalation

## Code Standards

```python
# Security test automation framework
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Callable
from enum import Enum
import asyncio
import httpx
import re
from urllib.parse import urljoin, urlparse, parse_qs


class Severity(Enum):
    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
    INFO = "info"


@dataclass
class Finding:
    """Security finding."""
    title: str
    severity: Severity
    description: str
    evidence: str
    remediation: str
    cwe: Optional[str] = None
    cvss: Optional[float] = None
    endpoint: Optional[str] = None
    parameter: Optional[str] = None


@dataclass
class SecurityTestResult:
    """Result of a security test."""
    test_name: str
    passed: bool
    findings: List[Finding] = field(default_factory=list)
    duration: float = 0.0


class SecurityScanner:
    """Automated security scanner."""

    def __init__(self, base_url: str, auth_token: Optional[str] = None):
        self.base_url = base_url
        self.auth_token = auth_token
        self.findings: List[Finding] = []
        self.client = httpx.AsyncClient(
            timeout=30.0,
            follow_redirects=False,
            verify=True,
        )

    async def close(self):
        await self.client.aclose()

    def _get_headers(self) -> Dict[str, str]:
        headers = {"User-Agent": "SecurityScanner/1.0"}
        if self.auth_token:
            headers["Authorization"] = f"Bearer {self.auth_token}"
        return headers

    async def test_sql_injection(self, endpoint: str, params: Dict[str, str]) -> List[Finding]:
        """Test for SQL injection vulnerabilities."""
        findings = []
        payloads = [
            "' OR '1'='1",
            "1; DROP TABLE users--",
            "1' AND '1'='1",
            "1 UNION SELECT NULL--",
            "' OR 1=1--",
            "admin'--",
            "1'; WAITFOR DELAY '0:0:5'--",
        ]

        error_patterns = [
            r"SQL syntax.*MySQL",
            r"Warning.*mysql_",
            r"PostgreSQL.*ERROR",
            r"ORA-\d{5}",
            r"Microsoft SQL Server",
            r"SQLITE_ERROR",
            r"SQLite3::SQLException",
            r"Unclosed quotation mark",
        ]

        for param_name, original_value in params.items():
            for payload in payloads:
                test_params = params.copy()
                test_params[param_name] = payload

                try:
                    response = await self.client.get(
                        urljoin(self.base_url, endpoint),
                        params=test_params,
                        headers=self._get_headers(),
                    )

                    content = response.text.lower()

                    # Check for SQL errors
                    for pattern in error_patterns:
                        if re.search(pattern, response.text, re.IGNORECASE):
                            findings.append(Finding(
                                title="SQL Injection Vulnerability",
                                severity=Severity.CRITICAL,
                                description=f"SQL injection detected in parameter '{param_name}'",
                                evidence=f"Payload: {payload}\nResponse contained SQL error",
                                remediation="Use parameterized queries or prepared statements",
                                cwe="CWE-89",
                                cvss=9.8,
                                endpoint=endpoint,
                                parameter=param_name,
                            ))
                            break

                    # Time-based detection
                    if "WAITFOR" in payload or "SLEEP" in payload:
                        if response.elapsed.total_seconds() > 4:
                            findings.append(Finding(
                                title="Blind SQL Injection (Time-based)",
                                severity=Severity.CRITICAL,
                                description=f"Time-based SQL injection in '{param_name}'",
                                evidence=f"Payload: {payload}\nResponse delayed by {response.elapsed.total_seconds()}s",
                                remediation="Use parameterized queries or prepared statements",
                                cwe="CWE-89",
                                endpoint=endpoint,
                                parameter=param_name,
                            ))

                except Exception as e:
                    pass  # Continue testing

        return findings

    async def test_xss(self, endpoint: str, params: Dict[str, str]) -> List[Finding]:
        """Test for Cross-Site Scripting vulnerabilities."""
        findings = []
        payloads = [
            "<script>alert('XSS')</script>",
            "'\"><script>alert('XSS')</script>",
            "<img src=x onerror=alert('XSS')>",
            "<svg onload=alert('XSS')>",
            "javascript:alert('XSS')",
            "<body onload=alert('XSS')>",
            "'-alert('XSS')-'",
            "<iframe src=\"javascript:alert('XSS')\">",
        ]

        for param_name, original_value in params.items():
            for payload in payloads:
                test_params = params.copy()
                test_params[param_name] = payload

                try:
                    response = await self.client.get(
                        urljoin(self.base_url, endpoint),
                        params=test_params,
                        headers=self._get_headers(),
                    )

                    # Check if payload is reflected
                    if payload in response.text:
                        findings.append(Finding(
                            title="Reflected XSS Vulnerability",
                            severity=Severity.HIGH,
                            description=f"XSS payload reflected in parameter '{param_name}'",
                            evidence=f"Payload: {payload}\nPayload found in response",
                            remediation="Encode output and validate input",
                            cwe="CWE-79",
                            cvss=6.1,
                            endpoint=endpoint,
                            parameter=param_name,
                        ))
                        break  # Found one, move to next param

                except Exception:
                    pass

        return findings

    async def test_authentication(self, login_endpoint: str) -> List[Finding]:
        """Test authentication security."""
        findings = []

        # Test default credentials
        default_creds = [
            ("admin", "admin"),
            ("admin", "password"),
            ("admin", "123456"),
            ("root", "root"),
            ("test", "test"),
        ]

        for username, password in default_creds:
            try:
                response = await self.client.post(
                    urljoin(self.base_url, login_endpoint),
                    json={"username": username, "password": password},
                    headers=self._get_headers(),
                )

                if response.status_code == 200:
                    findings.append(Finding(
                        title="Default Credentials",
                        severity=Severity.CRITICAL,
                        description=f"Default credentials work: {username}:{password}",
                        evidence=f"Login successful with {username}:{password}",
                        remediation="Remove or change default credentials",
                        cwe="CWE-798",
                        endpoint=login_endpoint,
                    ))
            except Exception:
                pass

        # Test for username enumeration
        try:
            valid_user = await self.client.post(
                urljoin(self.base_url, login_endpoint),
                json={"username": "admin", "password": "wrong"},
                headers=self._get_headers(),
            )
            invalid_user = await self.client.post(
                urljoin(self.base_url, login_endpoint),
                json={"username": "nonexistent_user_12345", "password": "wrong"},
                headers=self._get_headers(),
            )

            if valid_user.text != invalid_user.text:
                findings.append(Finding(
                    title="Username Enumeration",
                    severity=Severity.MEDIUM,
                    description="Different responses for valid/invalid usernames",
                    evidence="Response differs based on username validity",
                    remediation="Use generic error messages for login failures",
                    cwe="CWE-204",
                    endpoint=login_endpoint,
                ))
        except Exception:
            pass

        return findings

    async def test_security_headers(self, endpoint: str = "/") -> List[Finding]:
        """Test for missing security headers."""
        findings = []
        required_headers = {
            "Strict-Transport-Security": {
                "severity": Severity.MEDIUM,
                "description": "Missing HSTS header",
                "remediation": "Add Strict-Transport-Security header",
            },
            "X-Content-Type-Options": {
                "severity": Severity.LOW,
                "description": "Missing X-Content-Type-Options header",
                "remediation": "Add X-Content-Type-Options: nosniff",
            },
            "X-Frame-Options": {
                "severity": Severity.MEDIUM,
                "description": "Missing clickjacking protection",
                "remediation": "Add X-Frame-Options: DENY or SAMEORIGIN",
            },
            "Content-Security-Policy": {
                "severity": Severity.MEDIUM,
                "description": "Missing Content Security Policy",
                "remediation": "Implement a strict CSP",
            },
            "X-XSS-Protection": {
                "severity": Severity.LOW,
                "description": "Missing XSS protection header",
                "remediation": "Add X-XSS-Protection: 1; mode=block",
            },
        }

        try:
            response = await self.client.get(
                urljoin(self.base_url, endpoint),
                headers=self._get_headers(),
            )

            for header, info in required_headers.items():
                if header.lower() not in [h.lower() for h in response.headers.keys()]:
                    findings.append(Finding(
                        title=f"Missing Security Header: {header}",
                        severity=info["severity"],
                        description=info["description"],
                        evidence=f"Header '{header}' not present in response",
                        remediation=info["remediation"],
                        cwe="CWE-693",
                        endpoint=endpoint,
                    ))

            # Check for information disclosure
            if "Server" in response.headers:
                findings.append(Finding(
                    title="Server Version Disclosure",
                    severity=Severity.LOW,
                    description="Server header reveals version information",
                    evidence=f"Server: {response.headers['Server']}",
                    remediation="Remove or obfuscate Server header",
                    cwe="CWE-200",
                    endpoint=endpoint,
                ))

        except Exception:
            pass

        return findings

    async def test_cors(self, endpoint: str = "/api") -> List[Finding]:
        """Test CORS configuration."""
        findings = []
        origins_to_test = [
            "https://evil.com",
            "https://attacker.example.com",
            "null",
        ]

        for origin in origins_to_test:
            try:
                response = await self.client.options(
                    urljoin(self.base_url, endpoint),
                    headers={
                        **self._get_headers(),
                        "Origin": origin,
                        "Access-Control-Request-Method": "GET",
                    },
                )

                acao = response.headers.get("Access-Control-Allow-Origin", "")

                if acao == "*":
                    findings.append(Finding(
                        title="Permissive CORS Policy",
                        severity=Severity.MEDIUM,
                        description="CORS allows all origins",
                        evidence="Access-Control-Allow-Origin: *",
                        remediation="Restrict CORS to specific trusted origins",
                        cwe="CWE-942",
                        endpoint=endpoint,
                    ))
                    break

                if acao == origin:
                    acac = response.headers.get("Access-Control-Allow-Credentials", "")
                    if acac.lower() == "true":
                        findings.append(Finding(
                            title="CORS Misconfiguration with Credentials",
                            severity=Severity.HIGH,
                            description=f"CORS reflects origin '{origin}' with credentials",
                            evidence=f"Reflects {origin} with Allow-Credentials: true",
                            remediation="Don't reflect arbitrary origins with credentials",
                            cwe="CWE-942",
                            endpoint=endpoint,
                        ))

            except Exception:
                pass

        return findings

    async def run_full_scan(self, endpoints: List[Dict]) -> Dict:
        """Run comprehensive security scan."""
        all_findings = []

        # Security headers
        all_findings.extend(await self.test_security_headers())

        # CORS
        all_findings.extend(await self.test_cors())

        # Test each endpoint
        for ep in endpoints:
            endpoint = ep["path"]
            params = ep.get("params", {})

            if params:
                all_findings.extend(await self.test_sql_injection(endpoint, params))
                all_findings.extend(await self.test_xss(endpoint, params))

            if "login" in endpoint.lower():
                all_findings.extend(await self.test_authentication(endpoint))

        self.findings = all_findings

        return self.generate_report()

    def generate_report(self) -> Dict:
        """Generate security report."""
        severity_counts = {s.value: 0 for s in Severity}
        for finding in self.findings:
            severity_counts[finding.severity.value] += 1

        return {
            "summary": {
                "total_findings": len(self.findings),
                "by_severity": severity_counts,
                "risk_score": self._calculate_risk_score(),
            },
            "findings": [
                {
                    "title": f.title,
                    "severity": f.severity.value,
                    "description": f.description,
                    "evidence": f.evidence,
                    "remediation": f.remediation,
                    "cwe": f.cwe,
                    "endpoint": f.endpoint,
                    "parameter": f.parameter,
                }
                for f in sorted(self.findings, key=lambda x: list(Severity).index(x.severity))
            ],
        }

    def _calculate_risk_score(self) -> float:
        """Calculate overall risk score."""
        weights = {
            Severity.CRITICAL: 10,
            Severity.HIGH: 7,
            Severity.MEDIUM: 4,
            Severity.LOW: 1,
            Severity.INFO: 0,
        }
        total = sum(weights[f.severity] for f in self.findings)
        return min(100, total)


# Example usage
async def main():
    scanner = SecurityScanner(
        base_url="https://example.com",
        auth_token="test-token",
    )

    endpoints = [
        {"path": "/api/users", "params": {"id": "1", "name": "test"}},
        {"path": "/api/search", "params": {"q": "test"}},
        {"path": "/api/login", "params": {}},
    ]

    try:
        report = await scanner.run_full_scan(endpoints)
        print(json.dumps(report, indent=2))
    finally:
        await scanner.close()


if __name__ == "__main__":
    asyncio.run(main())
```

```yaml
# Security testing in CI/CD
# .github/workflows/security.yml
name: Security Tests

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  schedule:
    - cron: "0 2 * * *"

jobs:
  sast:
    name: Static Analysis
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Semgrep
        uses: returntocorp/semgrep-action@v1
        with:
          config: >-
            p/security-audit
            p/secrets
            p/owasp-top-ten

      - name: Run Bandit (Python)
        if: hashFiles('**/*.py') != ''
        run: |
          pip install bandit
          bandit -r . -f json -o bandit-report.json || true

      - name: Upload SAST results
        uses: actions/upload-artifact@v4
        with:
          name: sast-results
          path: |
            semgrep.sarif
            bandit-report.json

  dependency-scan:
    name: Dependency Scanning
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Snyk
        uses: snyk/actions/python@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

      - name: Run Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: CRITICAL,HIGH

  dast:
    name: Dynamic Analysis
    runs-on: ubuntu-latest
    needs: [sast]
    steps:
      - uses: actions/checkout@v4

      - name: Start application
        run: |
          docker-compose up -d
          sleep 30

      - name: Run OWASP ZAP
        uses: zaproxy/action-full-scan@v0.8.0
        with:
          target: "http://localhost:8080"
          rules_file_name: ".zap/rules.tsv"
          cmd_options: "-a"

      - name: Run Nuclei
        run: |
          docker run --network host projectdiscovery/nuclei \
            -u http://localhost:8080 \
            -severity critical,high \
            -json -o nuclei-results.json

      - name: Stop application
        run: docker-compose down

  secret-scanning:
    name: Secret Scanning
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Run Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Run TruffleHog
        run: |
          docker run --rm -v $(pwd):/repo \
            trufflesecurity/trufflehog \
            git file:///repo --json > trufflehog-results.json
```

## Best Practices

### Testing Strategy

- Integrate security testing in CI/CD
- Combine SAST, DAST, and manual testing
- Test in staging before production
- Automate repetitive tests

### Vulnerability Management

- Prioritize by severity and exploitability
- Track remediation progress
- Verify fixes with retesting
- Document all findings

### Continuous Improvement

- Update testing tools regularly
- Add tests for new vulnerabilities
- Learn from incidents
- Train development teams

### Compliance

- Map tests to requirements
- Maintain audit trails
- Generate compliance reports
- Regular security assessments

You implement comprehensive security testing programs with automated scanning and manual penetration testing.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…