# Pentest Lyan Web Security Testing

> Autonomous web penetration testing skill with threat modeling, JavaScript analysis, and multi-role verification

- Skill: `aradotso-security-skills/pentest-lyan-web-security-testing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aradotso-security-skills/pentest-lyan-web-security-testing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aradotso-security-skills/pentest-lyan-web-security-testing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: aradotso (https://skillmd.com/u/aradotso-security-skills)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/aradotso-security-skills/pentest-lyan-web-security-testing

---


# Pentest-Lyan Web Security Testing

> Skill by [ara.so](https://ara.so) — Security Skills collection.

Pentest-Lyan is an autonomous web penetration testing framework that performs self-directed threat modeling across 12 dimensions, complete JavaScript analysis, and cross-role verification. It validates business impact (not just HTTP 200 responses), maintains state across sessions, and generates both technical Markdown and delivery-ready Word reports.

## What It Does

- **Autonomous Threat Modeling**: Identifies threats based on 12 thinking dimensions rather than fixed vulnerability checklists
- **Deep JavaScript Analysis**: Reads and understands business logic, signing mechanisms, and frontend parameters before testing APIs
- **Business Impact Validation**: Verifies database-layer changes, data access, and state transitions actually occur
- **Multi-Role Testing**: Builds permission matrices and performs cross-role privilege escalation checks
- **Stateful Testing**: Supports resume (`--resume`), multi-project isolation, and session pooling
- **Dual Report Formats**: Markdown for technical details, Word for delivery; separates critical findings from configuration issues

## Installation

### Prerequisites

1. **Python 3.8+** with the project dependencies
2. **Playwright MCP Server** (recommended for browser automation and session pooling)

### Setup Steps

```bash
# Clone the repository
git clone https://github.com/HeaSec/Pentest-Lyan.git
cd Pentest-Lyan

# Install Python dependencies (if requirements.txt exists)
pip install -r requirements.txt

# Install as a Claude Code skill
# Copy the entire pentest-lyan/ directory to your Claude Code skills path
# Default locations:
#   - macOS/Linux: ~/.config/claude-code/skills/
#   - Windows: %APPDATA%\claude-code\skills\

cp -r . ~/.config/claude-code/skills/pentest-lyan/
```

### Playwright MCP Setup (Optional but Recommended)

```bash
# Install Playwright MCP for browser automation
npm install -g @playwright/mcp-server

# Or add to your MCP configuration
# The skill will use curl if Playwright is unavailable
```

## Project Structure

```
pentest-lyan/
├── SKILL.md              # Main orchestrator (3 phases, 9 exit conditions)
├── gates.md              # HARD GATE definitions (G1-G7)
├── schema.md             # Data schema index
├── references/           # Process documentation (read by agent as needed)
│   ├── discovery-guide.md
│   ├── attack-guide.md
│   ├── threat-modeling.md
│   ├── validation-guide.md
│   ├── cross-role-testing.md
│   ├── audit-guide.md
│   ├── report-template.md
│   ├── docx-template.md
│   └── post-delivery.md
├── schema/              # Field specification schemas (*.schema.json)
├── scripts/             # Utility scripts
│   └── render_docx.py
└── templates/           # Word document templates
```

## Basic Usage

### Starting a New Security Test

```bash
# Basic invocation
/pentest-lyan https://target.example.com

# Provide credentials (required for proper testing)
/pentest-lyan https://target.example.com
账号:
  - admin/Admin@123   (role_level: high_privilege)
  - user1/User@123    (role_level: standard)
  - user2/User@123    (role_level: standard)
```

**Important**: No need to declare authorization scope/timeframe — issuing the command implies authorization.

### Multi-Project Management

```bash
# List all projects
/pentest-lyan --list

# Resume an existing project
/pentest-lyan --resume <project-id>

# Start with custom project ID
/pentest-lyan https://target.example.com --project custom-id
```

Default `project-id` is extracted from the hostname's first segment.

## Testing Phases

Pentest-Lyan executes in three sequential phases:

### Phase 1: Discovery

- Deep JavaScript analysis (business logic, signing, parameters)
- Complete API endpoint discovery
- Session pool creation
- Permission matrix generation

### Phase 2: Attack

- Feature-level testing pipeline
- Dynamic sub-module discovery
- Cross-role privilege verification
- Business impact validation

### Phase 3: Audit

- Schema validation
- Completeness auditing
- System-level checks
- Report generation (Markdown + Word)

## Account Requirements (G1 Gate)

The G1 gate checks account availability but **does not block** testing:

- **≥2 accounts**: Normal flow, full cross-role testing
- **0-1 accounts**: Degraded mode, limited privilege testing; if registration page found, report prompts user to register additional accounts

`role_level` must be explicitly declared by the user (not inferred from username):
- `high_privilege`: Admin, superuser, manager
- `standard`: Regular user
- `limited`: Guest, read-only

## Working with State Files

Pentest-Lyan maintains state in `pentest-data/<project-id>/`:

```
pentest-data/
└── <project-id>/
    ├── state.json           # Main state (phase, coverage, findings)
    ├── index.json           # Project metadata
    ├── pages/              # Discovered pages/APIs
    ├── sessions/           # Session data (contains credentials)
    ├── modules/            # Feature module state
    └── coverage/           # Coverage tracking
```

### State File Example

```json
{
  "project_id": "example-com",
  "phase": "discovery",
  "target": "https://example.com",
  "accounts": [
    {
      "username": "admin",
      "password": "REDACTED",
      "role_level": "high_privilege"
    }
  ],
  "discovered_endpoints": [],
  "findings": [],
  "coverage": {}
}
```

**Security Warning**: `pentest-data/` contains plaintext credentials. Add to `.gitignore`:

```bash
# Add to .gitignore
echo "pentest-data/" >> .gitignore
echo "pentest-report/" >> .gitignore
```

## Threat Modeling Dimensions

Pentest-Lyan uses 12 autonomous threat dimensions:

1. **Authentication**: Session, token, multi-factor bypasses
2. **Authorization**: Horizontal/vertical privilege escalation, IDOR
3. **Input Validation**: Injection, XSS, path traversal
4. **Business Logic**: Workflow bypasses, race conditions
5. **Data Exposure**: Sensitive data leaks, information disclosure
6. **Session Management**: Fixation, hijacking, timeout issues
7. **Cryptography**: Weak algorithms, improper key management
8. **Configuration**: Default credentials, unnecessary services
9. **API Security**: Rate limiting, parameter tampering
10. **File Handling**: Upload bypasses, arbitrary file operations
11. **Error Handling**: Stack traces, verbose errors
12. **Third-Party**: Dependency vulnerabilities, external service abuse

## Code Examples

### Extending Validation Logic (Python)

```python
# Example: Custom validator for business impact
# File: custom_validators.py

import requests
import json

def validate_discount_manipulation(session, endpoint, payload):
    """
    Verify that discount manipulation actually affects the database.
    Returns True if vulnerability is confirmed.
    """
    # Apply discount
    resp = session.post(
        endpoint,
        json=payload,
        headers={"Content-Type": "application/json"}
    )
    
    if resp.status_code != 200:
        return False
    
    # Retrieve order to confirm database change
    order_id = resp.json().get("order_id")
    verify_resp = session.get(f"/api/orders/{order_id}")
    
    if verify_resp.status_code == 200:
        order_data = verify_resp.json()
        expected_price = payload.get("discounted_price")
        actual_price = order_data.get("total_price")
        
        # Confirm business impact
        return actual_price == expected_price
    
    return False

# Use in validation-guide.md workflow
```

### Reading JavaScript for Signing Logic

```python
# Example: Extracting signing mechanism from JS
# The agent performs this during discovery phase

import re
import requests

def extract_signing_function(js_url):
    """
    Download and parse JavaScript to find signing functions.
    """
    resp = requests.get(js_url)
    js_content = resp.text
    
    # Look for common signing patterns
    signing_patterns = [
        r'function\s+sign\([^)]*\)\s*{([^}]+)}',
        r'const\s+sign\s*=\s*\([^)]*\)\s*=>\s*{([^}]+)}',
        r'\.sign\s*=\s*function\([^)]*\)\s*{([^}]+)}'
    ]
    
    for pattern in signing_patterns:
        matches = re.findall(pattern, js_content)
        if matches:
            return {
                "signing_function": matches[0],
                "algorithm": detect_algorithm(matches[0])
            }
    
    return None

def detect_algorithm(func_body):
    """Detect crypto algorithm from function body."""
    if 'md5' in func_body.lower():
        return 'md5'
    elif 'sha256' in func_body.lower():
        return 'sha256'
    elif 'hmac' in func_body.lower():
        return 'hmac'
    return 'unknown'
```

### Permission Matrix Generation

```python
# Example: Building permission matrix for cross-role testing
# File: permission_matrix.py

def build_permission_matrix(endpoints, sessions):
    """
    Test each endpoint with each role to build permission matrix.
    Returns matrix of {endpoint: {role: accessible}}.
    """
    matrix = {}
    
    for endpoint in endpoints:
        matrix[endpoint["path"]] = {}
        
        for session_info in sessions:
            role = session_info["role_level"]
            session = session_info["session"]
            
            # Test access
            resp = session.get(
                endpoint["url"],
                allow_redirects=False
            )
            
            # Determine if accessible
            accessible = resp.status_code in [200, 201, 204]
            matrix[endpoint["path"]][role] = {
                "accessible": accessible,
                "status_code": resp.status_code
            }
    
    return matrix

# Example matrix output:
# {
#   "/api/admin/users": {
#     "high_privilege": {"accessible": True, "status_code": 200},
#     "standard": {"accessible": False, "status_code": 403}
#   },
#   "/api/profile": {
#     "high_privilege": {"accessible": True, "status_code": 200},
#     "standard": {"accessible": True, "status_code": 200}
#   }
# }
```

### Cross-Role Privilege Testing

```python
# Example: Test privilege escalation using permission matrix
# File: cross_role_test.py

def test_privilege_escalation(matrix, sessions):
    """
    Use permission matrix to find privilege escalation vulnerabilities.
    """
    findings = []
    
    for endpoint, roles in matrix.items():
        # Find endpoints accessible to high_privilege but not standard
        if (roles.get("high_privilege", {}).get("accessible") and
            not roles.get("standard", {}).get("accessible")):
            
            # Test with standard user using high_privilege user's ID
            standard_session = get_session_by_role(sessions, "standard")
            high_priv_user_id = get_user_id_by_role(sessions, "high_privilege")
            
            # Attempt access with victim ID (not hardcoded)
            test_url = endpoint.replace("{user_id}", str(high_priv_user_id))
            resp = standard_session.get(test_url)
            
            if resp.status_code in [200, 201]:
                findings.append({
                    "type": "privilege_escalation",
                    "endpoint": endpoint,
                    "description": f"Standard user can access high_privilege endpoint",
                    "evidence": {
                        "url": test_url,
                        "status": resp.status_code,
                        "attacker_role": "standard",
                        "victim_role": "high_privilege"
                    }
                })
    
    return findings
```

## Report Generation

### Markdown Report

Generated automatically at end of audit phase:

```bash
# Reports are written to:
pentest-report/<project-id>_<timestamp>.md
```

Structure:
- Executive Summary
- Findings (Critical → High → Medium → Low)
- Coverage Analysis (answers: input surface, behavior surface, depth)
- Appendix (configuration issues, not_vulnerable with unruled_out)

### Word Report

```python
# scripts/render_docx.py
import sys
from docx import Document
from docx.shared import Inches, Pt, RGBColor

def render_docx(markdown_path, output_path, template_path=None):
    """
    Convert Markdown report to Word document.
    
    Args:
        markdown_path: Path to .md report
        output_path: Path for output .docx
        template_path: Optional custom template
    """
    doc = Document(template_path) if template_path else Document()
    
    with open(markdown_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Parse markdown and apply styles
    sections = parse_markdown(content)
    
    for section in sections:
        if section['type'] == 'heading1':
            doc.add_heading(section['text'], level=1)
        elif section['type'] == 'finding':
            add_finding_block(doc, section['data'])
        elif section['type'] == 'code':
            add_code_block(doc, section['text'])
    
    doc.save(output_path)

# Usage:
# python scripts/render_docx.py pentest-report/example-com_2026.md output.docx
```

## Configuration

### Environment Variables

```bash
# Optional: Custom data directory
export PENTEST_DATA_DIR="/secure/location/pentest-data"

# Optional: Report output directory
export PENTEST_REPORT_DIR="/reports"

# Optional: Playwright MCP endpoint
export PLAYWRIGHT_MCP_URL="http://localhost:3000"

# Optional: Rate limiting (requests per second)
export PENTEST_RATE_LIMIT="5"

# Optional: Timeout for requests (seconds)
export PENTEST_TIMEOUT="30"
```

### Custom Gate Configuration

Edit `gates.md` to adjust gate thresholds:

```markdown
# G1: Account Gate
Threshold: ≥2 accounts (degraded mode if fewer)

# G2: JavaScript Coverage Gate
Threshold: ≥80% of main bundles analyzed

# G3: Endpoint Discovery Gate
Threshold: ≥5 unique endpoints or complete sitemap
```

## Common Patterns

### Pattern 1: Testing with Multiple Accounts

```python
# The framework automatically manages session pools
# You provide credentials at invocation:

/pentest-lyan https://api.example.com
Accounts:
  - admin@example.com/SecurePass123! (role_level: high_privilege)
  - user@example.com/UserPass456! (role_level: standard)
  - guest@example.com/GuestPass789! (role_level: limited)
```

### Pattern 2: Resuming After Interruption

```bash
# List projects to find ID
/pentest-lyan --list

# Output:
# example-com | Phase: attack | Findings: 3 | Status: in_progress

# Resume
/pentest-lyan --resume example-com
```

### Pattern 3: Custom Threat Module

Create a custom module in `references/custom-threats/`:

```markdown
# custom-payment-logic.md

## Threat: Payment Amount Manipulation

**Coverage Questions:**
- Input surface: price, quantity, discount_code, currency
- Behavior surface: calculate_total, apply_discount, process_payment
- Depth: Database transaction verification, audit log check

**Test Steps:**
1. Capture legitimate payment request
2. Modify `amount` parameter to $0.01
3. Replay request
4. Verify database: SELECT amount FROM orders WHERE order_id = ?
5. Check audit logs for amount mismatch

**Validation:**
- Status 200 alone is NOT sufficient
- Must confirm database shows manipulated amount
- Must confirm payment gateway charged manipulated amount
```

## Troubleshooting

### Issue: "No endpoints discovered"

**Cause**: JavaScript not fully analyzed or SPA routing not detected.

**Solution**:
```bash
# Check if JS bundles were downloaded
ls pentest-data/<project-id>/pages/

# Verify Playwright MCP is running
curl http://localhost:3000/health

# Force re-discovery
rm pentest-data/<project-id>/state.json
/pentest-lyan --resume <project-id>
```

### Issue: "G1 gate: insufficient accounts"

**Cause**: Fewer than 2 accounts provided.

**Solution**: This is a **soft gate** — testing continues in degraded mode.
- Provide additional accounts and re-run
- Or continue and register accounts manually if prompted in report

### Issue: "Validation failed: status 200 but no business impact"

**Cause**: Response is 200 but database/state unchanged.

**Solution**: This is **correct behavior** (not a bug).
- Pentest-Lyan requires verification of actual state change
- Check validation-guide.md for proper validation steps
- Customize validators if needed (see Code Examples above)

### Issue: Session expires during testing

**Cause**: Long-running tests exceed session timeout.

**Solution**:
```python
# Pentest-Lyan auto-refreshes sessions
# If custom session handling needed, extend:

# File: custom_session_refresh.py
def refresh_session(session_info):
    """Re-authenticate if session expired."""
    login_resp = requests.post(
        f"{session_info['base_url']}/api/login",
        json={
            "username": session_info["username"],
            "password": session_info["password"]
        }
    )
    return login_resp.cookies.get("session_token")
```

### Issue: Report missing findings

**Cause**: Findings not properly recorded in state.json.

**Solution**:
```bash
# Validate state file structure
python -c "
import json
with open('pentest-data/<project-id>/state.json') as f:
    state = json.load(f)
    print(f'Findings: {len(state.get(\"findings\", []))}')
"

# Check findings schema
cat schema/findings.schema.json
```

### Issue: Word report rendering fails

**Cause**: Missing python-docx or template corruption.

**Solution**:
```bash
# Install dependencies
pip install python-docx

# Re-render with default template
python scripts/render_docx.py \
  pentest-report/<project-id>.md \
  output.docx

# Or specify custom template
python scripts/render_docx.py \
  pentest-report/<project-id>.md \
  output.docx \
  --template templates/custom-template.docx
```

## Security Best Practices

1. **Credential Management**:
   - Never commit `pentest-data/` to version control
   - Use environment variables for sensitive config
   - Follow post-delivery cleanup (see `references/post-delivery.md`)

2. **Authorization**:
   - Only test systems you have explicit permission to test
   - Issuing `/pentest-lyan <target>` implies authorization

3. **Data Handling**:
   - Encrypt `pentest-data/` and `pentest-report/` after testing
   - Clear sessions after delivery: `rm -rf pentest-data/<project-id>/sessions/`

4. **Rate Limiting**:
   - Set `PENTEST_RATE_LIMIT` to avoid overwhelming targets
   - Default: 5 req/s (configurable)

## Advanced Usage

### Custom Validation Pipeline

```python
# File: advanced_validation.py

from typing import Dict, Any, List

def extended_validation_pipeline(finding: Dict[str, Any]) -> bool:
    """
    Extended validation requiring multiple confirmation steps.
    """
    validators = [
        validate_http_response,
        validate_database_state,
        validate_audit_log,
        validate_side_effects
    ]
    
    results = []
    for validator in validators:
        result = validator(finding)
        results.append(result)
        
        # Log validation step
        log_validation_step(
            finding_id=finding['id'],
            validator=validator.__name__,
            result=result
        )
    
    # All validators must pass
    return all(results)

def validate_database_state(finding: Dict[str, Any]) -> bool:
    """Verify database reflects the exploit."""
    # Implementation specific to finding type
    pass

def validate_audit_log(finding: Dict[str, Any]) -> bool:
    """Check if suspicious activity was logged."""
    # Absence of logging may itself be a finding
    pass

def validate_side_effects(finding: Dict[str, Any]) -> bool:
    """Verify no unintended side effects occurred."""
    pass
```

### Integration with CI/CD

```yaml
# .github/workflows/security-test.yml
name: Automated Security Testing

on:
  schedule:
    - cron: '0 2 * * 0'  # Weekly on Sunday 2 AM

jobs:
  pentest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      
      - name: Install Pentest-Lyan
        run: |
          git clone https://github.com/HeaSec/Pentest-Lyan.git
          cd Pentest-Lyan
          pip install -r requirements.txt
      
      - name: Run Security Test
        env:
          TEST_ADMIN_USER: ${{ secrets.TEST_ADMIN_USER }}
          TEST_ADMIN_PASS: ${{ secrets.TEST_ADMIN_PASS }}
          TEST_USER_USER: ${{ secrets.TEST_USER_USER }}
          TEST_USER_PASS: ${{ secrets.TEST_USER_PASS }}
        run: |
          /pentest-lyan https://staging.example.com \
            --account "$TEST_ADMIN_USER/$TEST_ADMIN_PASS (role_level: high_privilege)" \
            --account "$TEST_USER_USER/$TEST_USER_PASS (role_level: standard)"
      
      - name: Upload Report
        uses: actions/upload-artifact@v3
        with:
          name: security-report
          path: pentest-report/*.md
```

## Additional Resources

- [Threat Modeling Reference](references/threat-modeling.md) — 12 dimension framework
- [Cross-Role Testing Guide](references/cross-role-testing.md) — Permission matrix usage
- [Validation Guide](references/validation-guide.md) — Business impact verification
- [Schema Guide](references/schema-guide.md) — State file structure
- [Report Templates](references/report-template.md) — Markdown report structure
- [Post-Delivery Checklist](references/post-delivery.md) — Cleanup procedures

---

**License**: MIT  
**Repository**: https://github.com/HeaSec/Pentest-Lyan  
**Issues**: https://github.com/HeaSec/Pentest-Lyan/issues

