Back to Blog
Features7 min read

Webhooks, Slack, and CI: Connecting AI Pentest Results to Your Incident Workflow

P

Pentestas Team

Security Analyst

4/21/2026
Webhooks, Slack, and CI: Connecting AI Pentest Results to Your Incident Workflow

2026-04-21 · Pentestas Features

Every finding is an event. Feed them into your SIEM, Jira, PagerDuty, GitHub Security tab, or Slack — automatically.

Pentestas event bus Slack #secops PagerDuty (CRITICAL) Jira auto-ticket GitHub Security (SARIF) Splunk / Sentinel SIEM ServiceNow incident

Findings are events. Events fan out to your incident-response stack.

💰

In Detail

The event model

Pentestas emits the following events:

EventPayload
scan.createdscan_id, tenant_id, target_url, created_at
scan.startedscan_id, started_at
scan.progressscan_id, phase, message (throttled, not per-event)
scan.completedscan_id, findings_count, severity_breakdown, target_url, timestamp
scan.failedscan_id, error
finding.createdfinding (full schema)
finding.status_changedfinding_id, from, to, changed_by
agent.connectedagent_id, hostname
agent.disconnectedagent_id, reason

Subscribe to any subset per webhook. Events are signed with HMAC-SHA256 + your per-webhook secret so you can verify authenticity before trusting them.

⚙️

In Detail

Slack — zero-code

Fastest integration. Settings → Integrations → Slack → paste an incoming-webhook URL → save. A test message fires immediately to confirm the URL is live. From then on, every scan completion posts a rich message:

🚨 Scan complete: https://app.example.com
  Findings: 42 total (3 critical, 8 high, 15 medium, 16 low)
  Chain: "Path traversal → SSH keys → lateral" (CRITICAL)
  [View results →]

Colour:

  • Red — any CRITICAL.
  • Orange — HIGH but no CRITICAL.
  • Green — no HIGH/CRITICAL.

Pro+ adds:

  • **Only alert on new CRITICAL / HIGH*— throttles noisy scans.
  • **Thread under scheduled-scan parent*— long-running schedule posts one parent; each run replies in the thread. Channel stays clean.
  • **Custom Go-template body*— {{.Scan}}, {{.Findings}}, {{.TopChain}} variables for custom formatting.
📈

In Detail

Webhooks — arbitrary HTTPS

For any destination Slack doesn't cover, outbound webhooks drop JSON on any HTTPS URL. Configure in Settings → Webhooks:

  • URL (HTTPS enforced).
  • Events subscribed.
  • HMAC secret.
  • Description (freeform).

Pentestas sends a webhook.test event on save to confirm. Delivery failures (5xx, timeout > 10s) retry with exponential backoff: 30s, 2min, 10min, 1h, 6h, 24h. After 6 failed attempts, the delivery goes to the dead-letter queue + an in-app notification fires. The webhook itself isn't disabled — future events still fire.

Verification

Every request carries an X-Pentestas-Signature header:

X-Pentestas-Signature: sha256=<hex>

Where <hex> is HMAC-SHA256(secret, raw_body). Verify in your handler before trusting anything:

import hmac, hashlib
def verify(secret: str, sig_header: str, body: bytes) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    provided = sig_header.split("=", 1)[1]
    return hmac.compare_digest(expected, provided)

Always compare_digest — string equality leaks timing information.

📦

In Detail

Jira — ticket-per-finding

Webhook handler that POSTs to Jira's REST API on finding.created:

@app.post("/pentestas-webhook")
def handle():
    event = request.get_json()
    if event["event"] != "finding.created":
        return "ok", 200
    finding = event["finding"]
    if finding["severity"] not in ("CRITICAL", "HIGH"):
        return "ok", 200
    jira_client.create_issue(
        project=os.environ["JIRA_PROJECT"],
        summary=f"[{finding['severity']}] {finding['title']}",
        description=f"""
Endpoint: {finding['endpoint']}
CVSS: {finding['cvss_score']} ({finding['cvss_vector']})
CWE: {finding['cwe_id']}
OWASP: {finding['owasp_category']}

Evidence:
{finding['evidence']}

Remediation:
{finding['recommendation']}

Pentestas: https://app.pentestas.com/scan-detail/{event['scan_id']}#finding-{finding['id']}
        """,
        labels=["pentestas", finding["vuln_type"].lower()],
        priority="Highest" if finding["severity"] == "CRITICAL" else "High",
    )
    return "ok", 200

On finding.status_changedfixed, close the Jira ticket. Clean bi-directional flow.

⚠️

In Detail

PagerDuty — page on CRITICAL

@app.post("/pentestas-webhook")
def handle():
    event = request.get_json()
    if event["event"] != "scan.completed":
        return "ok", 200
    if event.get("severity_breakdown", {}).get("CRITICAL", 0) == 0:
        return "ok", 200
    pagerduty.trigger_incident(
        service=os.environ["PD_SERVICE_KEY"],
        incident_key=f"pentestas-{event['scan_id']}",
        summary=f"Pentestas: CRITICAL finding on {event['target_url']}",
        details=event,
    )
    return "ok", 200

De-dupe with the incident_key = scan_id pattern so re-firing on a subsequent scan against the same target doesn't spam.

🔍

Scanning

ServiceNow — incident-per-scan

The same shape as Jira but pointed at ServiceNow's Table API. Enterprise customers often add ServiceNow-specific fields (business_service, assignment_group, category) on top of the core schema.

🛡️

Security

GitHub Security tab — SARIF export

- name: Pentestas scan
  env:
    PENTESTAS_API_KEY: ${{ secrets.PENTESTAS_API_KEY }}
  run: |
    pentestas start -u https://staging-${{ github.sha }}.example.com -c .pentestas/scan.yaml -w 30m
    scan_id=$(pentestas list --status completed --limit 1 | head -1 | awk '{print $1}')
    curl -H "X-API-Key: ${PENTESTAS_API_KEY}" \
         "https://app.pentestas.com/api/scans/${scan_id}/report?format=sarif" \
         -o pentestas.sarif

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: pentestas.sarif

Findings light up in the repo's Security tab with file-level annotations (when white-box mode supplied source-code citations). Engineers see them in the same UI as their CodeQL, Dependabot, and secret-scanning findings.

🛡️

In Detail

SIEM integration (Splunk, Sentinel, Datadog)

Every SIEM supports HTTP event-collector endpoints. Webhook → HEC URL:

@app.post("/pentestas-webhook")
def handle():
    event = request.get_json()
    requests.post(
        os.environ["SPLUNK_HEC_URL"],
        json={
            "source": "pentestas",
            "sourcetype": "pentestas:" + event["event"],
            "event": event,
        },
        headers={"Authorization": f"Splunk {os.environ['SPLUNK_HEC_TOKEN']}"},
    )
    return "ok", 200

Scan-completion rate, finding-creation trend, average-time-to-fix per severity — all become native Splunk dashboards with a few SPL queries against the resulting event stream.

🔥

In Detail

Rate limits + reliability

  • 50 events / minute per webhook URL.
  • **10,000-event buffer.*If your destination is down for a while, Pentestas buffers up to 10K events; past that, oldest events drop.
  • **Successful response:*any 2xx. Anything else (including 3xx redirects) is treated as failure and retried.
  • **Idempotency:*every event includes an event_id. Destinations should de-dupe on event_id — replays happen.
💰

In Detail

Delivery log

Settings → Webhooks → click a webhook → Delivery log. Shows the last 100 deliveries with request / response / latency. Click any to see the full JSON body. Replay button re-fires a specific delivery if your destination was down or had a transient bug.

This is the single most-used debugging feature when wiring a new integration. Expect to use it every time you add a new webhook.

💼

By Industry

Industry scenarios

Fintech

Chain — finding → Jira → engineer fix → Slack notification on resolve → SIEM trend update. Full lifecycle visible to every stakeholder. Compliance officer looks at the SIEM dashboard quarterly; CISO looks at the Slack summary; engineers work in Jira. Each consumer gets their native interface.

Medtech

Chain — CRITICAL finding → PagerDuty page → incident opened in ServiceNow → HIPAA-adjacent review triggered. Fast triage on the PHI-sensitivity findings. Monthly trend reporting to the HIPAA compliance programme manager via SIEM.

Legaltech

Chain — client-facing attestation need → scheduled PDF export via webhook → store in client-share drive. Automated evidence generation for enterprise RFP responses.

Banks + insurance

Chain — scan completion → SIEM ingest → risk-management-system trend → quarterly risk-committee dashboard. Board-visible testing cadence without manual curation.

📈

In Detail

Getting started

  • For Slack: 2 minutes. Paste incoming-webhook URL. Done.
  • For Jira / PagerDuty: 30 minutes of handler code. Ship it to an existing HTTPS endpoint (AWS Lambda, Cloudflare Worker, dedicated service).
  • For SIEM: 15 minutes. Point the webhook at your HEC URL.
  • For GitHub: one CI job change. See the CLI post.

The integration pattern scales to every downstream system. Pentestas doesn't care where findings go; the API surface makes sure they can go wherever your programme needs.

Wire your first Pentestas integration

Register, run a scan, add a Slack webhook. First finding lands in your channel the same day.

Start your AI pentest
📚

More Reading

Further reading

Alexander Sverdlov

Alexander Sverdlov

Founder of Pentestas. Author of 2 information security books, cybersecurity speaker at the largest cybersecurity conferences in Asia and a United Nations conference panelist. Former Microsoft security consulting team member, external cybersecurity consultant at the Emirates Nuclear Energy Corporation.