Guides for DevSecOps Engineers
These guides cover automation workflows: CI/CD integration, API usage, webhook notifications, and API spec imports for maximum scan coverage.
Guide 1: Integrating ThreatWeaver into CI/CD Pipelinesβ
Shift security left by triggering vulnerability scans automatically when code changes.
| Time needed | 30 minutes |
| Prerequisites | ThreatWeaver API token; access to your CI/CD configuration |
| What you'll learn | How to trigger scans from GitHub Actions and GitLab CI, and fail builds on critical findings |
How it worksβ
GitHub Actions setupβ
Create a workflow file in your repository:
# .github/workflows/security-scan.yml
name: Security Scan
on:
pull_request:
branches: [main, develop]
jobs:
dast-scan:
runs-on: ubuntu-latest
steps:
- name: Trigger ThreatWeaver Scan
id: scan
env:
TW_API_TOKEN: ${{ secrets.TW_API_TOKEN }}
TW_TARGET_ID: ${{ secrets.TW_TARGET_ID }}
run: |
RESPONSE=$(curl -s -X POST \
-H "Authorization: Bearer $TW_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"targetId\": \"$TW_TARGET_ID\"}" \
https://api.threatweaver.ai/api/appsec/assessments/trigger)
ASSESSMENT_ID=$(echo $RESPONSE | jq -r '.assessmentId')
echo "assessment_id=$ASSESSMENT_ID" >> $GITHUB_OUTPUT
- name: Poll for Completion
env:
TW_API_TOKEN: ${{ secrets.TW_API_TOKEN }}
run: |
ASSESSMENT_ID="${{ steps.scan.outputs.assessment_id }}"
for i in $(seq 1 60); do
STATUS=$(curl -s \
-H "Authorization: Bearer $TW_API_TOKEN" \
"https://api.threatweaver.ai/api/appsec/assessments/$ASSESSMENT_ID" \
| jq -r '.status')
if [ "$STATUS" = "completed" ]; then
echo "Scan completed!"
break
fi
echo "Scan in progress (attempt $i/60)..."
sleep 30
done
- name: Check for Critical Findings
env:
TW_API_TOKEN: ${{ secrets.TW_API_TOKEN }}
run: |
ASSESSMENT_ID="${{ steps.scan.outputs.assessment_id }}"
CRITICAL_COUNT=$(curl -s \
-H "Authorization: Bearer $TW_API_TOKEN" \
"https://api.threatweaver.ai/api/appsec/assessments/$ASSESSMENT_ID/findings?severity=critical" \
| jq '.totalCount')
if [ "$CRITICAL_COUNT" -gt 0 ]; then
echo "FAIL: Found $CRITICAL_COUNT critical vulnerabilities!"
exit 1
fi
echo "PASS: No critical vulnerabilities found."
Add TW_API_TOKEN and TW_TARGET_ID as encrypted secrets in your repository settings. Never hardcode credentials in workflow files.
GitLab CI setupβ
# .gitlab-ci.yml
security-scan:
stage: test
script:
- |
RESPONSE=$(curl -s -X POST \
-H "Authorization: Bearer $TW_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"targetId\": \"$TW_TARGET_ID\"}" \
https://api.threatweaver.ai/api/appsec/assessments/trigger)
ASSESSMENT_ID=$(echo $RESPONSE | jq -r '.assessmentId')
echo "Assessment started: $ASSESSMENT_ID"
# Poll and check results (same logic as GitHub Actions)
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
Failing builds on critical findingsβ
You can configure your pipeline to:
| Policy | Action |
|---|---|
| Critical findings | Fail the build immediately -- block the merge. |
| High findings | Warn but allow merge (with reviewer approval). |
| Medium and below | Log for tracking, do not block. |
When first integrating, set the policy to warn-only. Once your team has addressed the initial backlog, switch to blocking on Critical and High findings.
Guide 2: Using the ThreatWeaver APIβ
Automate any ThreatWeaver workflow programmatically using the REST API.
| Time needed | 20 minutes to get started |
| Prerequisites | ThreatWeaver account with API access |
| What you'll learn | How to authenticate, make API calls, and automate common workflows |
Getting your API tokenβ
- Log in to ThreatWeaver.
- Navigate to Settings > Security.
- Under API Tokens, click Generate Token.
- Copy the token immediately -- it will not be shown again.
API tokens inherit the permissions of the user who created them. Create a dedicated service account with the minimum required role for automated workflows.
Making your first API callβ
List all assets:
curl -s \
-H "Authorization: Bearer YOUR_API_TOKEN" \
https://api.threatweaver.ai/api/assets \
| jq '.data[:3]'
Common workflowsβ
Create a target and start a scanβ
# Step 1: Create a target
TARGET=$(curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Staging API", "url": "https://staging.api.myapp.com"}' \
https://api.threatweaver.ai/api/appsec/targets)
TARGET_ID=$(echo $TARGET | jq -r '.id')
# Step 2: Start a scan
ASSESSMENT=$(curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"targetId\": \"$TARGET_ID\", \"scanType\": \"gray_box\"}" \
https://api.threatweaver.ai/api/appsec/assessments/trigger)
ASSESSMENT_ID=$(echo $ASSESSMENT | jq -r '.assessmentId')
echo "Scan started: $ASSESSMENT_ID"
# Step 3: Poll for results
while true; do
STATUS=$(curl -s \
-H "Authorization: Bearer $TOKEN" \
"https://api.threatweaver.ai/api/appsec/assessments/$ASSESSMENT_ID" \
| jq -r '.status')
[ "$STATUS" = "completed" ] && break
sleep 30
done
# Step 4: Get findings
curl -s \
-H "Authorization: Bearer $TOKEN" \
"https://api.threatweaver.ai/api/appsec/assessments/$ASSESSMENT_ID/findings" \
| jq '.data[] | {type: .vulnerabilityType, severity: .severity, endpoint: .endpoint}'
Get all critical findings for a targetβ
curl -s \
-H "Authorization: Bearer $TOKEN" \
"https://api.threatweaver.ai/api/appsec/findings?targetId=$TARGET_ID&severity=critical" \
| jq '.data'
Export findings as SARIFβ
SARIF (Static Analysis Results Interchange Format) is supported by GitHub, VS Code, and other developer tools.
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/sarif+json" \
"https://api.threatweaver.ai/api/appsec/assessments/$ASSESSMENT_ID/export?format=sarif" \
-o results.sarif
Rate limitsβ
| Endpoint Category | Limit |
|---|---|
| Read operations (GET) | 100 requests/minute |
| Write operations (POST/PUT/DELETE) | 30 requests/minute |
| Scan triggers | 10 requests/minute |
- Cache responses where possible to reduce API calls.
- Use webhook notifications instead of polling for scan completion.
- Implement exponential backoff when you hit rate limits.
Guide 3: Setting Up Webhooks and Notificationsβ
Get notified automatically when scans complete, new findings are discovered, or findings are resolved.
| Time needed | 15 minutes |
| Prerequisites | Admin role; a webhook endpoint (e.g., Slack incoming webhook URL) |
| What you'll learn | How to configure webhooks and integrate with Slack and PagerDuty |
Available webhook eventsβ
| Event | When it fires |
|---|---|
scan_completed | A scan finishes (success or failure). |
finding_created | A new vulnerability is discovered. |
finding_resolved | A previously open vulnerability is confirmed fixed. |
finding_reopened | A previously fixed vulnerability has reappeared. |
exception_expiring | An exception is about to expire (7 days before). |
Configuring a webhookβ
- Navigate to Admin > Integrations.
- Click "+ Add Webhook".
- Enter the webhook URL -- the HTTPS endpoint that will receive events.
- Select events -- choose which events trigger the webhook.
- Save and test. Click Send Test to verify your endpoint receives the payload.
Webhook payload formatβ
{
"event": "finding_created",
"timestamp": "2026-04-04T10:30:00Z",
"data": {
"findingId": "f-abc123",
"vulnerabilityType": "sql_injection",
"severity": "critical",
"endpoint": "POST /api/users/search",
"assessmentId": "a-def456",
"targetName": "Staging API"
}
}
Integrating with Slackβ
- In Slack, create an Incoming Webhook for your security channel (Slack workspace settings > Apps > Incoming Webhooks).
- Copy the webhook URL (starts with
https://hooks.slack.com/services/...). - In ThreatWeaver, add this URL as a webhook and select the events you care about.
- Slack will receive formatted messages for each event.
Integrating with PagerDutyβ
For critical findings that need immediate attention:
- In PagerDuty, create an Events API v2 integration on your security service.
- Copy the integration key.
- In ThreatWeaver, add a PagerDuty integration under Admin > Integrations.
- Configure it to trigger only on
finding_createdevents withcriticalseverity. - Your on-call engineer will be paged immediately when a critical vulnerability is found.
ThreatWeaver signs webhook payloads with an HMAC signature in the X-TW-Signature header. Verify this signature on your endpoint to ensure the webhook came from ThreatWeaver and was not tampered with.
Guide 4: Importing API Specs for Better Scanningβ
Providing an API specification tells the scanner exactly which endpoints exist, what parameters they accept, and what data types are expected. This dramatically improves scan coverage.
| Time needed | 10 minutes |
| Prerequisites | An API specification file (OpenAPI, Swagger, Postman, or GraphQL schema) |
| What you'll learn | How to upload API specs and troubleshoot missing endpoint coverage |
Why API specs improve scanningβ
Without a spec, the scanner discovers endpoints by crawling and guessing. With a spec, it knows every endpoint from the start.
Supported formatsβ
| Format | File Extension | Notes |
|---|---|---|
| OpenAPI 3.0+ | .json, .yaml | Preferred. Full parameter and schema support. |
| Swagger 2.0 | .json, .yaml | Automatically converted to OpenAPI 3.0. |
| Postman Collection | .json | v2.1 collections supported. |
| GraphQL Schema | .graphql, .gql | Introspection query results also accepted. |
Steps: Upload via UIβ
- Navigate to AppSec > Targets.
- Select your target and click Edit.
- In the API Specification section, click Upload Spec.
- Select your file and click Upload. ThreatWeaver will parse the spec and show a summary (number of endpoints, parameters, and schemas detected).
- Save the target. The next scan will use the spec for full endpoint coverage.
Steps: Upload via APIβ
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-F "spec=@openapi.yaml" \
"https://api.threatweaver.ai/api/appsec/targets/$TARGET_ID/spec"
Troubleshooting: "My scan missed endpoints"β
| Symptom | Cause | Fix |
|---|---|---|
| Endpoints in spec not scanned | Spec not attached to target | Re-upload the spec and verify it is listed on the target page. |
| Some endpoints return 404 | Base URL mismatch | Check that the target URL matches the servers section in your OpenAPI spec. |
| POST endpoints not tested | Missing request body schemas | Add requestBody definitions to your spec so the scanner knows what payloads to send. |
| GraphQL mutations missed | Introspection disabled | Provide the schema file directly instead of relying on introspection. |
Re-upload your API spec whenever you add new endpoints. Outdated specs mean the scanner misses new attack surface.
Next stepsβ
- Setting Up Authenticated Scanning -- combine auth + API specs for maximum coverage
- Configuring Tenable API Keys -- connect the vulnerability management side
- Tracking Remediation Progress -- close the loop on discovered vulnerabilities
- FAQ -- answers to common questions