Skill: youdaolee/page-behavior-audit (version 1.0.7)

--- name: page-behavior-audit description: Deep behavioral audit with hashed policy (CSP-compliant, no plaintext badwords) homepage: https://github.com/openclaw/page-behavior-audit metadata: { "openclaw": { "emoji": "🔍", "type": "skill", "version": "1.0.3", "modelInvocable": false, "requiredEnv": [ { "name": "WECOM_WEBHOOK_URL", "description": "WeCom webhook URL for critical alerts", "sensitive": true, }, { "name": "OPENCLAW_AUDIT_DIR", "description": "Directory for audit logs, screenshots, and HAR files", "default": "${HOME}/.openclaw/audit", }, ], "trigger": { "type": "webhook", "path": "/api/audit/scan", "method": "POST" }, "timeout": 15000, }, } --- # page-behavior-audit Deep behavioral page auditing with content safety policy enforcement. ## Features - 🔍 Browser automation with redirect tracking - 🛡️ Content policy checking (hashed badwords) - 🎯 Response monitoring (SSRF/XXE detection) - 📸 Full-page screenshots - 📊 HAR export - 🚨 WeCom alerts for critical findings ## Prerequisites Set required environment variables: ```bash export WECOM_WEBHOOK_URL="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY" export OPENCLAW_AUDIT_DIR="${HOME}/.openclaw/audit" # optional ``` ## Usage ### Via Webhook ```bash curl -X POST http://localhost:8080/api/audit/scan \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com", "include_har": true}' ``` ### Via CLI ```bash openclaw skill run page-behavior-audit --url https://example.com ``` ## Configuration **Input schema:** - `url` (string, required): Target URL to audit - `include_har` (boolean, optional): Export HAR file (default: true) **Output:** - `redirects`: Captured redirects - `text_alerts`: Content policy violations - `ct_alerts`: Response monitoring alerts - `screenshot_path`: Screenshot file path - `har_path`: HAR file path ## Security - SHA256-hashed badword policies - Ed25519 signature verification - CSP-compliant (no plaintext sensitive words) - Sandbox-isolated browser execution ## Alert Rules **CRITICAL severity:** - XML served from non-.xml endpoints (SSRF/XXE risk) - Image endpoints returning XML (XXE evasion) Alerts are sent to WeCom webhook when critical issues are detected.

path: install.sh
content: #!/bin/bash

# OpenClaw Skill Installer
# Page Behavior Audit v1.0.3

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

SKILL_NAME="page-behavior-audit"
SKILL_VERSION="1.0.3"
USE_SUDO=false

echo -e "${GREEN}=== OpenClaw Skill Installer ===${NC}"
echo -e "Skill: ${YELLOW}${SKILL_NAME}${NC}"
echo -e "Version: ${YELLOW}${SKILL_VERSION}${NC}"
echo ""

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --user)
            USE_SUDO=false
            shift
            ;;
        --system)
            USE_SUDO=true
            shift
            ;;
        *)
            echo -e "${RED}Unknown option: $1${NC}"
            echo "Usage: $0 [--user|--system]"
            echo "  --user   : Install to user directory (default, no sudo required)"
            echo "  --system : Install to system directory (requires sudo)"
            exit 1
            ;;
    esac
done

# Check if OpenClaw is installed
if ! command -v openclaw &> /dev/null; then
    echo -e "${YELLOW}Warning: OpenClaw CLI not found${NC}"
    echo "Attempting manual installation..."
    MANUAL_INSTALL=true
else
    echo -e "${GREEN}✓ OpenClaw CLI detected${NC}"
    MANUAL_INSTALL=false
fi

# Set installation directories based on mode
if [ "$USE_SUDO" = true ]; then
    INSTALL_DIR="${OPENCLAW_HOME:-/etc/openclaw}/skills"
    AUDIT_DIR="/var/log/openclaw/audit"
    echo -e "${BLUE}Installation mode: System (requires sudo)${NC}"
else
    INSTALL_DIR="${OPENCLAW_HOME:-$HOME/.openclaw}/skills"
    AUDIT_DIR="${OPENCLAW_AUDIT_DIR:-$HOME/.openclaw/audit}"
    echo -e "${BLUE}Installation mode: User (no sudo required)${NC}"
fi

echo ""
echo "Checking directories..."

# Create skills directory
if [ ! -d "$INSTALL_DIR" ]; then
    echo -e "${YELLOW}Creating skills directory: $INSTALL_DIR${NC}"
    if [ "$USE_SUDO" = true ]; then
        sudo mkdir -p "$INSTALL_DIR" || {
            echo -e "${RED}Failed to create $INSTALL_DIR${NC}"
            exit 1
        }
    else
        mkdir -p "$INSTALL_DIR" || {
            echo -e "${RED}Failed to create $INSTALL_DIR${NC}"
            exit 1
        }
    fi
fi

# Create audit directory
if [ ! -d "$AUDIT_DIR" ]; then
    echo -e "${YELLOW}Creating audit directory: $AUDIT_DIR${NC}"
    if [ "$USE_SUDO" = true ]; then
        sudo mkdir -p "$AUDIT_DIR" || {
            echo -e "${YELLOW}Warning: Failed to create $AUDIT_DIR${NC}"
        }
    else
        mkdir -p "$AUDIT_DIR" || {
            echo -e "${YELLOW}Warning: Failed to create $AUDIT_DIR${NC}"
        }
    fi
fi

# Install the skill
echo ""
SKILL_FILE="$INSTALL_DIR/${SKILL_NAME}.yaml"

if [ "$MANUAL_INSTALL" = true ]; then
    echo "Installing skill manually..."
    if [ "$USE_SUDO" = true ]; then
        sudo cp skill.yaml "$SKILL_FILE" || {
            echo -e "${RED}Failed to copy skill.yaml${NC}"
            exit 1
        }
    else
        cp skill.yaml "$SKILL_FILE" || {
            echo -e "${RED}Failed to copy skill.yaml${NC}"
            exit 1
        }
    fi
    echo -e "${GREEN}✓ Skill installed to: $SKILL_FILE${NC}"
else
    echo "Installing skill via OpenClaw CLI..."
    openclaw skill install skill.yaml || {
        echo -e "${RED}Failed to install via CLI, trying manual install...${NC}"
        if [ "$USE_SUDO" = true ]; then
            sudo cp skill.yaml "$SKILL_FILE"
        else
            cp skill.yaml "$SKILL_FILE"
        fi
        echo -e "${GREEN}✓ Skill installed to: $SKILL_FILE${NC}"
    }
fi

# Verify installation
echo ""
echo "Verifying installation..."
if [ -f "$INSTALL_DIR/${SKILL_NAME}.yaml" ] || openclaw skill list 2>/dev/null | grep -q "$SKILL_NAME"; then
    echo -e "${GREEN}✓ Installation successful!${NC}"
else
    echo -e "${RED}✗ Installation verification failed${NC}"
    exit 1
fi

# Post-install instructions
echo ""
echo -e "${GREEN}=== Installation Complete ===${NC}"
echo ""
echo -e "${YELLOW}IMPORTANT: Configure required environment variables:${NC}"
echo ""
echo "  export WECOM_WEBHOOK_URL='https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY'"
echo "  export OPENCLAW_AUDIT_DIR='$AUDIT_DIR'"
echo ""
echo "Add these to your ~/.bashrc or ~/.zshrc to persist across sessions."
echo ""
echo "Usage:"
echo "  1. Via Webhook:"
echo "     curl -X POST http://localhost:8080/api/audit/scan \\"
echo "       -H 'Content-Type: application/json' \\"
echo "       -d '{\"url\": \"https://example.com\"}'"
echo ""
echo "  2. Via CLI:"
echo "     openclaw skill run ${SKILL_NAME} --url https://example.com"
echo ""
echo "  3. Via UI:"
echo "     Visit http://localhost:8080/skills/${SKILL_NAME}"
echo ""
echo "Audit logs will be saved to: $AUDIT_DIR"
echo ""
if [ "$USE_SUDO" = true ]; then
    echo -e "${YELLOW}Note: You may need to restart OpenClaw for changes to take effect${NC}"
    echo "      sudo systemctl restart openclaw"
else
    echo -e "${YELLOW}Note: Restart OpenClaw to load the new skill${NC}"
fi


path: README.md
content: # page-behavior-audit

OpenClaw Skill for deep behavioral page auditing with hashed policy.

## Installation

```bash
npx clawhub@latest install page-behavior-audit
```

## Required Environment Variables

```bash
export WECOM_WEBHOOK_URL="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
export OPENCLAW_AUDIT_DIR="${HOME}/.openclaw/audit"  # optional
```

## Usage

```bash
curl -X POST http://localhost:8080/api/audit/scan \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
```

## Version

1.0.3

## License

MIT


path: package.json
content: {
  "name": "page-behavior-audit",
  "version": "1.0.3",
  "description": "Deep behavioral audit with hashed policy (CSP-compliant, no plaintext badwords)",
  "main": "SKILL.md",
  "keywords": [
    "openclaw",
    "skill",
    "security",
    "frontend",
    "supply-chain",
    "audit",
    "behavior-analysis"
  ],
  "author": "",
  "license": "MIT",
  "files": [
    "SKILL.md",
    "skill.yaml",
    "README.md"
  ]
}


path: skill.yaml
content: ---
name: "page-behavior-audit"
version: "1.0.3"
model_invocable: false
trigger:
  type: "webhook"
  path: "/api/audit/scan"
  method: "POST"
description: "Deep behavioral audit with hashed policy (CSP-compliant, no plaintext badwords)"
tags:
  - "security"
  - "frontend"
  - "supply-chain"
timeout: 15000
env:
  required:
    - name: "WECOM_WEBHOOK_URL"
      description: "WeCom webhook URL for critical alerts"
      sensitive: true
    - name: "OPENCLAW_AUDIT_DIR"
      description: "Directory for audit logs, screenshots, and HAR files"
      default: "${HOME}/.openclaw/audit"
ui:
  runnable: true
  input_schema:
    type: "object"
    properties:
      url:
        type: "string"
        format: "uri"
        description: "Target URL to audit (must be HTTP/HTTPS)"
      include_har:
        type: "boolean"
        default: true
    required:
      - "url"
policy:
  badwords:
    hash_list:
      # sha256 hashes for exact match keywords (64 hex chars)
      - "sha256:5e884898da28047151d0e56f8dc6292773607d2d72aa89a73c1b472a0765512e"
      - "sha256:2c74fd17edafd80e8447b0d4f3a7d62e86d5f3514d105a93e15596c8a1a1319f"
      - "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
    regex_hash_list:
      # sha256 hashes for regex patterns (64 hex chars)
      - "sha256:1f8ac10f7420b57ee1e8d77fec5c82892bb2d50e70631fe5bcb57cf342498114"
    source: "verified:internal://policy/content-safety/2026-q1"
    updated_at: "2026-02-10T08:00:00Z"
    signature: "ed25519:A1B2C3D4E5F6789012345678901234567890123456789012345678901234567890ABCDEF1234567890"
    verification_url: "https://your-org.example.com/policies/verify"

steps:
  - step: "launch-browser"
    action: "builtin.launchBrowser"
    config:
      headless: true
      args:
        - "--no-sandbox"
        - "--disable-gpu"
        - "--disable-dev-shm-usage"
        - "--user-data-dir=/tmp/openclaw-$(uuid)"

  - step: "navigate-and-wait"
    action: "builtin.navigate"
    depends_on:
      - "launch-browser"
    config:
      url: "{{ .input.url }}"
      wait_until: "networkidle0"
      timeout: "{{ .input.timeout | default 15000 }}"

  - step: "install-redirect-hook"
    action: "builtin.evaluate"
    depends_on:
      - "navigate-and-wait"
    config:
      expression: "() => { window.__oc_redirects = []; const orig = location.assign; location.assign = function(u) { __oc_redirects.push({type:'assign',url:u,ts:Date.now()}); orig.apply(this,arguments); }; location.replace = function(u) { __oc_redirects.push({type:'replace',url:u,ts:Date.now()}); orig.apply(this,arguments); }; }"

  - step: "extract-content"
    action: "builtin.evaluate"
    depends_on:
      - "install-redirect-hook"
    config:
      expression: "({ title: document.title, text: document.body?.innerText?.substring(0, 10000) || '', links: Array.from(document.querySelectorAll('a[href]')).map(a => ({ href: a.href, text: a.textContent?.trim()?.substring(0, 200) || '' })).filter(x => x.href) })"

  - step: "check-text-policy"
    action: "builtin.checkTextPolicy"
    depends_on:
      - "extract-content"
    config:
      text: "{{ .steps.extract-content.output.text }}"
      links: "{{ .steps.extract-content.output.links }}"

  - step: "monitor-responses"
    action: "builtin.monitorResponses"
    depends_on:
      - "navigate-and-wait"
    config:
      rules:
        - condition: "headers['content-type'] && headers['content-type'].toLowerCase().includes('xml') && !url.match(/\\.xml($|\\?)/i)"
          severity: "CRITICAL"
          message: "XML served from non-.xml endpoint (SSRF/XXE risk)"
        - condition: "headers['content-type'] && headers['content-type'].toLowerCase().includes('image/') && body && body.trim().startsWith('<?xml')"
          severity: "CRITICAL"
          message: "Image endpoint returning XML (XML external entity evasion)"

  - step: "screenshot"
    action: "builtin.screenshot"
    depends_on:
      - "navigate-and-wait"
    config:
      path: "{{ env.OPENCLAW_AUDIT_DIR }}/$(date +%s)_{{ sha256 .input.url }}.png"
      full_page: true

  - step: "export-har"
    action: "builtin.harExport"
    depends_on:
      - "navigate-and-wait"
    config:
      path: "{{ env.OPENCLAW_AUDIT_DIR }}/$(date +%s)_{{ sha256 .input.url }}.har"

  - step: "aggregate-report"
    action: "builtin.aggregateReport"
    depends_on:
      - "check-text-policy"
      - "monitor-responses"
      - "screenshot"
      - "export-har"
    config:
      fields:
        url: "{{ .input.url }}"
        redirects: "{{ .steps.install-redirect-hook.output }}"
        text_alerts: "{{ .steps.check-text-policy.output.alerts }}"
        ct_alerts: "{{ .steps.monitor-responses.output.alerts }}"
        screenshot_path: "{{ .steps.screenshot.output.path }}"
        har_path: "{{ .steps.export-har.output.path }}"

  - step: "send-alert-if-critical"
    action: "builtin.notify"
    depends_on:
      - "aggregate-report"
    if: "{{ .steps.aggregate-report.output.critical_count > 0 }}"
    config:
      channel: "wecom"
      webhook_url: "{{ env.WECOM_WEBHOOK_URL }}"
      template: "FRONTEND_BEHAVIOR_ALERT"
      data:
        url: "{{ .input.url }}"
        alerts: "{{ json .steps.aggregate-report.output }}"


path: .claude/settings.local.json
content: {
  "permissions": {
    "allow": [
      "Bash(chmod:*)",
      "Bash(./verify.sh:*)",
      "Bash(bash:*)"
    ]
  }
}


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)