Skip to content
Back to skills

Source 958f3a0ac8c9e27a5d7baa5b

ASecurity

Runs the HawkScan DAST security loop — configure, scan, fix all reported vulnerabilities (not just your changes), rescan to verify. Performs code-first discovery to configure high-value scans, and quality-gates every scan against code-derived expectations before findings are parsed. Use when the user asks to run or perform a security/DAST scan, to test an app or API for vulnerabilities, or to verify a vulnerability is fixed; and AUTONOMOUSLY right after you complete a code change (feature, bu...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
securitygoshellbashsqlrailsdockertestinggitapidatabase

Works with

  • cursor
  • terminal
  • cli
  • api

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add gutsofpratik/OpenClaude-Skills --skill source-958f3a0ac8c9e27a5d7baa5b --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Source 958f3a0ac8c9e27a5d7baa5b?

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

Security grade badge for Source 958f3a0ac8c9e27a5d7baa5b
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gutsofpratik-source-958f3a0ac8c9e27a5d7baa5b/badge)](https://www.skillsdirectory.com/skills/gutsofpratik-source-958f3a0ac8c9e27a5d7baa5b)

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: hawkscan
version: 2.6.0
description: >
  Runs the HawkScan DAST security loop — configure, scan, fix all reported
  vulnerabilities (not just your changes), rescan to verify. Performs
  code-first discovery to configure high-value scans, and quality-gates every
  scan against code-derived expectations before findings are parsed. Use when
  the user asks to run or perform a security/DAST scan, to test an app or API
  for vulnerabilities, or to verify a vulnerability is fixed; and AUTONOMOUSLY
  right after you complete a code change (feature, bugfix, refactor) — "done"
  means "done and secure," so run the loop without asking permission. Do NOT
  trigger for: informational questions about what HawkScan is, detects, or how
  it works (e.g. "what vulnerabilities does HawkScan find?"); editing
  stackhawk.yml or other config without running a scan; querying existing
  findings, security posture, untriaged counts, or scan history (use the
  stackhawk-api skill); documentation-only changes; installing or setting up
  the CLI; or when the user explicitly says to skip scanning.
---

# HawkScan Skill

This skill enables Claude to act as the security testing orchestrator in an agentic
coding loop. The core workflow is:

**Code changes → Start Application/API → Configure HawkScan → Run scan → Parse findings → Generate fix tasks → Repeat**

---

## Prerequisites (preflight — run before anything else)

This skill requires **hawk v6.0.0 or newer**. Verify:

```bash
hawk version
hawk config --help >/dev/null 2>&1 || echo "MISSING: hawk config — upgrade hawk to v6.0.0+"
hawk skills status
```

If hawk is older than `6.0.0` or `hawk config --help` fails, stop and tell the user to
upgrade before proceeding. Do not inline auth recipes from memory — they live in
`hawk config show` and are stale by design when hardcoded.

**`hawk skills status`** reports whether the installed StackHawk agent skills are current.
If it lists anything out of date, surface the exact upgrade command it prints (e.g.
`/plugin marketplace update stackhawk && /plugin update hawkscan`) and recommend the user
update before continuing — a stale skill may be missing fixes for the very issues you'll hit.
It's a recommendation, not a hard stop: proceed if the user prefers. (If the subcommand isn't
recognized, the installed hawk predates it — skip this check.)

See `references/installation.md` for upgrade and install instructions.

---

## Companion Skills

The `api` skill wraps read-only StackHawk platform lookups via the `hawk` CLI (`hawk op …`):

| Purpose                       | Command                                                                          |
|-------------------------------|----------------------------------------------------------------------------------|
| Check if App exists           | `hawk op app list --format json`                                                  |
| Check if Env exists           | `hawk op env list --app <NAME\|UUID> --format json`                               |
| Get findings with triage      | `hawk op scan get --app <NAME\|UUID> --detail full --format json`                 |
| List ASM repos                | `hawk op repo list --format json`                                                 |
| Link app to ASM repo          | `hawk op repo link --repo-id <ID> --app-id <ID>`                                  |
| Get tech flags                | `hawk op app tech-flags get --app <NAME\|UUID> --format json`                     |
| Disable all tech flags        | `hawk op app tech-flags disable-all --app <NAME\|UUID> --yes`                     |
| Set specific tech flags       | `hawk op app tech-flags set --app <NAME\|UUID> Key=true`                          |
| Triage a finding              | `hawk op scan triage --scan <ID> --hash <HASH> --status false-positive --note ""` |
| Bulk triage from file         | `hawk op scan triage --scan <ID> --from-file triage.yaml`                         |
| Annotate w/o triage perm      | `hawk op finding note --scan <ID> --hash <HASH> --note "..."`                     |
| Get scanned URIs              | `hawk op scan uris <scanId> --format json` (skip if the subcommand errors)         |
| Get effective scan config     | `hawk op scan config <scanId>` (skip if the subcommand errors)                     |

These reads require the combined `hawk` CLI; the `api` skill covers setup (`hawk init --browser` or the `HAWK_API_KEY` env var).

**Selecting an app:** `--app` takes an application **name or UUID** — pass whichever you have (e.g. the `applicationId` from `stackhawk.yml`, or the app's name). No separate flag is needed. Also parse `--format json` output defensively — a "skills out of date" banner may precede the JSON.

The `stackhawk-data-seed` skill sets up checked-in backend seed data via `hawk perch seed`.
Hand off to it when authentication fails because the backend has no valid credential
(**Phase 1c.6**), or after a scan when auth succeeded but endpoints returned empty data
(**Step 6**). This skill then consumes its `.data-seed-credentials.env` handoff.

---

## StackHawk Platform Model (read this first)

Before running a scan, understand these four layered objects:

- **Organization** (`orgId`): the tenant. Implicit via `HAWK_API_KEY`.
- **Application** (`applicationId`, UUID): long-lived; holds tech flags and metadata. One App spans many Environments.
- **Environment** (`env`, string name): scan context under an App. Findings compare scan-to-scan *within the same env*.
- **Scan**: a single run. Tagged with commit SHA and branch for traceability.

**Non-negotiable rules:** Apps are reused, not created per scan. Envs group history — pick
names deliberately. Findings have a lifecycle (NEW, FALSE_POSITIVE, RISK_ACCEPTED, ASSIGNED) — respect it.

→ Deep reference: [`references/platform-model.md`](references/platform-model.md)

---

## Progress output

Keep the terminal informed so a running loop never looks silent. Prefix every status line with
`StackHawk | ` — **ASCII only, no emoji** (must render in Cursor, Windows `cmd`, and PowerShell;
keep the branded lines themselves plain ASCII). Emit one short line **entering each phase** —
discovery, config, scan, quality gate, findings, each fix batch, rescan, report — with what's
happening plus the key number (routes, coverage, findings). Before a scan/rescan, note it takes
a few minutes and let hawk's own progress stream through (don't suppress it); announce
completion after. Status output, **not** a prompt — never pause for input. E.g.
`StackHawk | Scanning http://localhost:8080 - a few minutes; progress streams below`, then
`StackHawk | 3 findings (2 High, 1 Medium) - fixing all`. Per-phase lines: `references/autonomous-loop.md`.

---

## Phase 0: App Setup & Verification

Run Phase 0 whenever a `stackhawk.yml` is being **created** — a new application, or a reused
app with a fresh config. Do NOT run on every scan (0a/0b are idempotent; 0c is non-destructive).

**Phase 0a — Repo Linking:** Associate the app with its source repo in Attack Surface
Management. Get the git remote URL, normalize it (lowercase, strip `.git`, strip host prefix
to `owner/repo`), match against `hawk op repo list --format json` output, and run
`hawk op repo link --repo-id <UUID> --app-id <UUID>`. If no match, inject a `git_origin` tag
into `stackhawk.yml`.
→ Full normalization rules and SSH/HTTPS edge cases: [`references/repo-linking.md`](references/repo-linking.md)

**Phase 0b — Agent Tagging:** Add the `_STACKHAWK_AGENT` tag to `stackhawk.yml` once if missing:
```yaml
tags:
  - name: _STACKHAWK_AGENT
    value: ${HAWK_AGENT:none}
```

**Phase 0c — Scan Policy & Tech Flags (via optimize):** Run the **optimize skill's Setup mode**
on **every fresh `stackhawk.yml`** — not only the first time an app is onboarded. Setup is
non-destructive (a named trial policy referenced via `app.scanPolicy.name`; the app's own flags
are untouched) and stays re-runnable via `/optimize`. Skipping it leaves the agent hand-building
a policy, which silently hits the traps in [`references/scan-policy.md`](references/scan-policy.md)
(dropped `STRENGTH_LOW`/`THRESHOLD_LOW`, lost passive rules) — read that file before any policy edit.
→ **Fallback** (no policy permissions): if optimize's `hawk op policy create --dry-run` reports
a missing `ORG_POLICY_MANAGEMENT` / `WRITE_POLICY` / feature flag, it degrades to recommend-only.
Then detect codebase evidence (package.json, pom.xml, go.mod, requirements.txt, Gemfile, *.csproj)
and, if found, disable all then enable only detected flags via `hawk op app tech-flags`; if none, skip.
→ Fallback detection heuristics + flag names: [`references/tech-flags.md`](references/tech-flags.md)

---

## Step 1: Assess Context

> **Env Name Algorithm** — used wherever an environment name must be resolved. First match wins:
> 1. `STACKHAWK_ENV` env var set → use it exactly
> 2. `CI=true` or `GITHUB_ACTIONS=true` → `CI`
> 3. Git branch `main`/`master`/`production` → `Production`; `staging` → `Staging`; otherwise → `Development`

### Step 1a: Discover What to Scan

Before generating config, run code-first discovery: find every API surface in the repo
(REST, GraphQL, gRPC, SPA, ...), derive a route inventory per surface, and get the run
command, host/port, and auth shape needed to reach each one. Prefer the repo's own docs
over guessing, explore code to fill gaps, and ask the user directly for whatever remains
unresolved — never stall or invent.

**Discovery is read-only and static.** Determine the run command, host, and port by
*reading* config and docs — `docker-compose.yml` port mappings, `.env`/`.env.example`
(e.g. `APP_URL`), the README — not by launching anything. You never need to start the app,
run a container, or bring up a server to discover *what* to scan; standing up the target is
a scan-time step (Step 1c), not part of discovery.

→ Full discovery workflow — per-surface detection, route-inventory derivation, gap
  recommendations, and the pre-scan summary (user-confirmed when interactive; headless: print
  it, proceed, and record each assumption as a `stackhawk.yml` comment):
  [`references/scan-planning.md`](references/scan-planning.md)
→ Docs-first source table (which files to read and what to harvest):
  [`references/app-discovery.md`](references/app-discovery.md)

Record what discovery produced — surfaces, run command, host/port, auth shape — Step 1c and
Step 2 consume them.

**SPA rule:** if the app is a client-rendered JS front end, never scan it without the Ajax
Spider, and note that a separate backend API is usually the higher-value target. Full
strategy, frontend-vs-backend scenarios, and config templates:
→ [`references/spa-scanning.md`](references/spa-scanning.md)

### Step 1c: Environment Checks (run in order)

1. **App running?** HawkScan requires a live target. Start it first if not running.
2. **`stackhawk.yml` present?** If missing → Step 2a (generate). If present → Step 2b (tune).
3. **Credentials?** Any **non-interactive session** (CI, container, headless agent): set `HAWK_API_KEY`
   and prefix every invocation with `API_KEY=$HAWK_API_KEY hawk <cmd>` — no `hawk init`, no browser;
   a 401/403 means the key is wrong or missing. Interactive only: `hawk init --browser` (re-run it on a later 401/403).
4. **Runtime?** Check `which hawk`. If found: use CLI. If not: check `docker --version`.
   If both absent: see `references/installation.md`.
5. **App exists?** Run `hawk op app list --format json`. Match by name (normalized: lowercased,
   `_` and `-` equivalent). Exactly one match → use its `applicationId`. Multiple matches →
   pick by host if established, else surface to user. No match → create:
   ```bash
   hawk create app --name "<repo-name>" --env <env-name>
   ```
   Resolve `<env-name>` with the Env Name Algorithm above. Announce it (Progress output):
   `StackHawk | Created app <name> (<appId>) - <url>`.
6. **Env exists?** Determine env name via Env Name Algorithm. Run
   `hawk op env list --app <APP_ID> --format json`. Reuse if exists; otherwise run
   `hawk op env create --app <APP_ID> --env <name> --host <url>`.

---

## Step 2a: Generate `stackhawk.yml` from Scratch

Use the `applicationId` and `env` from Step 1c. **Minimum viable config:**
```yaml
app:
  applicationId: ${APP_ID}
  env: ${APP_ENV:Development}
  host: ${APP_HOST:http://localhost:8080}
```

**Always use env var interpolation** (`${VAR:default}`) for sensitive values and anything
that varies across environments. Use `${VAR:default}` (single colon, not `${VAR:-default}`).
The entire YAML value must be the variable — `host: "https://${HOST}/api"` will NOT interpolate.

**Never create a separate `stackhawk.local.yml` for host overrides.** Use
`host: ${APP_HOST:https://your-default-host.com}` and override at runtime:
```bash
APP_HOST=http://localhost:3000 hawk scan
```

After writing `stackhawk.yml`, always validate:
```bash
timeout 30 hawk validate config stackhawk.yml || echo "Validate timed out — ensure hawk CLI 6.0.0+ is installed"
```
Do not proceed to Step 3 until validation passes.

→ API-type-specific config (OpenAPI, GraphQL, gRPC, seed paths, spider tuning):
  [`references/config-patterns.md`](references/config-patterns.md)
→ Input vectors — HAR seed for XML/non-JSON bodies, `customVariables` scoped per resource, and
  the reachable-sink rule for injection plugins: [`references/input-vectors.md`](references/input-vectors.md)

**REST surface? Get an accurate OpenAPI spec BEFORE the first scan — this is not optional.**
A REST scan with no spec (spider/`seedPaths` only) reaches a small fraction of the API; a
scan with a *wrong* spec 404s every path. Do not skip to a scan on the assumption a spec is
missing or "good enough" — **open and follow [`references/openapi-specs.md`](references/openapi-specs.md)** to
work its preference order (a spec the running app serves → a code/build change that generates
one → a spec published outside the repo → hand-derived), then run its resolve-check
(`host + spec-path` returns real routes, not 404s) before scanning. Reaching for
`hawk.spider.seedPaths` instead of a spec is a last resort, not a shortcut — read that file
first. Same idea for GraphQL/gRPC: wire the schema/proto, don't scan blind.

### Phase 1c: Authentication Configuration

Use `hawk config show` to fetch the canonical recipe for the app's auth pattern.

**Step 1 — List available auth methods:**
```bash
hawk config show app.authentication --text
```

**Step 2 — Pick one by observed app behavior:**

→ Auth pattern decision table: [`references/auth-config.md`](references/auth-config.md)

If no row matches → jump to **Phase 1c.5**. Do not force-fit a recipe or proceed without auth.

**One user, or `profiles` + `--profile-scan-mode=primary-full`.** A `profiles` block **without** that mode runs
only the hidden BUSINESS_LOGIC preset (BOLA/BFLA, 2 plugins, ~30 s, 0 general findings). Write profiles only when
BOLA/BFLA coverage is the goal and the installed hawk has the flag; a build without it must not use profiles.
Scan as a non-privileged user or pinned token; an admin scan can mutate its own login. → [`references/auth-config.md`](references/auth-config.md#profiles-and-scan-user)

**Step 3 — Fetch each relevant section:** `hawk config show <section> --text`. Use the returned YAML example as template.

**Step 4 — Always include a testPath:** `hawk config show app.authentication.testPath --text`. The `testPath` must return 401/403 without auth and 200 with auth.

**Step 5 — Validate before scanning** (mandatory whenever `authentication:` is authored or modified):
```bash
hawk validate config stackhawk.yml   # structural check
hawk validate auth stackhawk.yml     # live auth check
```

→ Full recipe steps and fetch commands: [`references/auth-config.md`](references/auth-config.md)

### Phase 1c.5: Auth Analyzer Fallback

Invoke when: (1) auth signals exist but pattern doesn't match any Phase 1c table row;
(2) `hawk validate auth` returned non-zero after Phase 1c (wrong recipe, not empty datastore);
(3) user explicitly requests interactive setup.

`hawk perch onboard` is the wizard — **interactive only** (a person logs in through Chrome). It runs the
validate-auth loop with structured per-field errors and streams JSONL phase events. Always run `hawk perch stop`
on every exit path. Headless: skip the wizard; build the block from `hawk config show app.authentication --text`.

→ Full flow, event handler matrix, error table, and re-run behavior:
  [`references/auth-analyzer-fallback.md`](references/auth-analyzer-fallback.md)

### Phase 1c.6: Seed Backend Data (empty datastore)

Use when the **recipe is correct** but auth fails because the credential doesn't exist in the
backend (fresh local stack, just-migrated database, empty users/api_key tables). Gate first:
```bash
hawk perch seed validate --help >/dev/null 2>&1 && hawk perch seed finalize --help >/dev/null 2>&1
```
If gate passes and `stackhawk-data-seed` is installed → invoke it. It produces
`.data-seed-credentials.env` which this skill then consumes. If hawk is too old → tell the
user to upgrade (`brew upgrade stackhawk/cli/hawk`, hawk ≥ `6.0.0`) or manually create the
dev credential. For gateway/multi-service apps, the credential lives in an upstream service's
datastore — run the seed against that repo, not the gateway.

After seeding, re-run `hawk validate auth stackhawk.yml` and continue.

---

## Step 2b: Tune Existing `stackhawk.yml`

Review the config against the current app state:

- **Gate reported gaps?** Tune what the gate names (wire spec, enable ajax spider, fix
  auth) — additive-only; see [`references/scan-quality.md`](references/scan-quality.md).
- **Low path count?** For a REST surface the fix is almost always an accurate spec — get one per `references/openapi-specs.md` (a wired, resolving `openApiConf` is worth far more than any spider tuning). Then: SPA/JS app → `hawk.spider.ajax: true`; GraphQL → wire `graphqlConf`. `hawk.spider.seedPaths` is a last resort (URLs only — no methods/bodies/params, so it can't reach POST/PUT or parameterized routes); prefer even a hand-derived spec over it, and omit it entirely once a spec is wired.
- **Auth failing?** Verify `authentication` block; re-fetch the relevant recipe via `hawk config show <section> --text` (Phase 1c).
- **Too noisy / too slow?** Add `app.excludePaths` or `app.includePaths`; tune `hawk.spider.maxDurationMinutes`. A follow-up full scan **prunes** (unused tech flags, noisy paths) or fixes auth/spec — it never raises strength or lowers threshold across all plugins ([`references/scan-policy.md`](references/scan-policy.md)).
- **New API type added?** Add corresponding `graphqlConf`, `openApiConf`, etc.
- **Need custom headers?** Use `hawkAddOn.replacer` for tenant or API version headers.
- **Running in CI?** Add commit SHA tags (top-level in `stackhawk.yml`, not under `app:`):
  ```yaml
  tags:
    - name: _STACKHAWK_GIT_COMMIT_SHA
      value: ${COMMIT_SHA:none}
    - name: _STACKHAWK_GIT_BRANCH
      value: ${BRANCH_NAME:none}
  ```

**Validate after any modification:**
```bash
timeout 30 hawk validate config stackhawk.yml || echo "Validate timed out — ensure hawk CLI 6.0.0+ is installed"
```

---

## Step 3: Validate and Run

> **Pre-flight:** Run scan commands synchronously — never with `&` or `nohup`. Wait for the exit code. Do not start a new scan while one is already running for this app/env. **First scan = one broad detected-stack policy, run to completion; if several full scans run, the broadest runs last** — the last completed scan is the result ([`references/scan-policy.md`](references/scan-policy.md)).

Set env vars, then validate:
```bash
export COMMIT_SHA=$(git rev-parse HEAD)
export BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
```

Export `HAWK_AGENT` using the platform + model detection block from
[`references/agent-detection.md`](references/agent-detection.md). Skip if `HAWK_AGENT` is
already set (CI/CD override).

```bash
hawk validate config stackhawk.yml
hawk validate api stackhawk.yml
if grep -qE '^\s*authentication:' stackhawk.yml; then
  hawk validate auth stackhawk.yml
fi
```

Run `hawk validate config` every time the config changes. Run `hawk validate api` when
adding or modifying OpenAPI spec references. Run `hawk validate auth` whenever the
`authentication:` block is new or modified — do not skip it. Fix all failures before scanning.

**Config file path rules (common agent mistake):** Validate and scan commands use positional
arguments only — no `-c` or `--config` flag. Use bare filenames (not absolute paths). See
[`references/cli-reference.md`](references/cli-reference.md#config-file-path-rules).

**Memory & crash detection:** the scanner heap defaults to 9g (`--hawk-mem`). A scan that dies with SIGABRT late
in the run exhausted it — raise `--hawk-mem`, never cut `hawk.scan.maxRuleDurationMinutes` (that truncates injection
rules). False "target crashed" aborts on slow endpoints → `hawk.scan.crashDetection.action: WARN`. See [`references/cli-reference.md`](references/cli-reference.md#memory-and-crash-detection).

### CLI Reference

→ Full command reference (flags, diagnostics, perch daemon, exit codes):
  [`references/cli-reference.md`](references/cli-reference.md)

**Quick reference for agentic scanning:**
```bash
hawk scan --json-output                            # structured output (requires Dev Release v5.3.41+)
hawk rescan --scan-id <SCAN_ID> --json-output      # fast fix verification — re-runs only fired plugins
```

**Always rescan against the original full-scan ID.** Rescan IDs are not valid parent scan references.

### Exit Codes
`0` complete, nothing at/above `failureThreshold` · `1` scan failed (config, unreachable, auth) ·
`42` complete, findings at/above `failureThreshold`. Table: [`references/cli-reference.md`](references/cli-reference.md#exit-codes)

---

## Step 4.5: Quality Gate

Run this gate after **every** scan — full scans and rescans alike, any exit code — before
parsing findings into fix tasks. Exception: on exit 1 where no scan was actually started
(config parse failure, app unreachable pre-scan), there is no `scanId` to gate against — skip
straight to Step 6's diagnosis / the environment-class path instead. It is a feedback loop
into config tuning, **not a governor**: gate state never blocks a finding from being reported
and fixed; a thin scan that missed surface can still have found something real.

Run the five checks and derive the expectation fresh each time, exactly as
`references/scan-quality.md` describes — coverage (evidence-only), base-path resolve, auth,
surface-completeness, and health.
On config-class gaps (`spec-not-wired`, `surface-unscanned`, `auth-validate-failed`,
`auth-wall`, `all-4xx`, `base-path-mismatch`), loop back to Step 2b with an additive-only fix, batch every gap
into one edit pass, and rescan once. Iteration cap: 2 interactive / 1 autonomous, per
config, counted in rescans. On environment-class gaps (`env-unreachable`), never edit
config — verify the app is up, retry once for free, and stop if it recurs. Multi-config
repos gate sequentially, one config at a time, immediately after that config's scan.

At the cap, or once checks are clean, proceed to Step 4 regardless — findings are always
reported and fixable. Never say a scan is "done and secure" while a gate gap is open; state
plainly what was scanned, what wasn't, and why, using the reason identifiers.

→ Full check definitions, commands, degradation when a subcommand is unavailable, and the
  iteration/reporting rules: [`references/scan-quality.md`](references/scan-quality.md)

---

## Step 4: Parse Findings and Generate Fix Tasks

Use `--json-output` for structured results (requires Dev Release v5.3.41+). Suppresses all
other stdout — do not combine with `--trace`. **Fix ALL findings** the scan reports — not just
findings related to recent changes. DAST scans the running application as a whole; a
pre-existing SQL injection is just as exploitable as one introduced today.

→ Full JSON schema, field reference, fix task format, and common findings guidance:
  [`references/findings-and-fixes.md`](references/findings-and-fixes.md)

→ Per-finding guidance on high-iteration findings (CSP, CORS, Auth, Missing Headers) — what
  "done" looks like, verify commands, escalation thresholds:
  [`references/high-iteration-findings.md`](references/high-iteration-findings.md)

**If the scan was slow, suggest optimize (once).** After a full scan, if it ran **≥ 20 minutes**
(wall-clock) OR stopped at its `hawk.spider.maxDurationMinutes` cap, surface a one-time suggestion:

> This scan was slow. Consider running `/optimize` to tune the scan policy from per-path
> metrics — it can lower concurrency for rate-limited paths and exclude heavy/slow paths.

This is a suggestion only — do **not** auto-run optimize. Surface it at most **once per session**,
and **only for full scans** — never for the rescans / fix-verification reruns in the Step 6 loop
(good scans can legitimately take a while; 20 min is the floor to avoid noise).

---

## Step 5: Filter Findings by Triage State

Filter by the per-path `status` field (`findings[].paths[].status`) before fixing:

- **SKIP** `FALSE_POSITIVE` or `RISK_ACCEPTED` paths — a human already decided these are not actionable. If every path of a finding is SKIP, skip the finding entirely.
- **PRIORITIZE** `ASSIGNED` paths before `NEW` of the same severity — confirmed real.
- **FIX** `NEW` paths in severity order: High → Medium → Low; within same severity: injection > auth bypass > IDOR > XSS > header issues.

**Marking false positives** — mark `NEW` findings that are clearly false positives before routing the rest to the fix loop:
```bash
hawk op scan triage --scan <SCAN_UUID> --hash <FINDING_HASH> --status false-positive \
  --note "<reason> [triaged by ${HAWK_AGENT:-agent}]"
```
Always append `[triaged by ${HAWK_AGENT:-agent}]` to every note for platform audit trail attribution.

**Rules:**
- ✅ Mark `FALSE_POSITIVE` autonomously with a clear reason note
- ❌ **Never mark `RISK_ACCEPTED` or `ASSIGNED`** — human decisions only
- ❌ Do NOT suppress findings in the codebase to hide scanner results
- ⚠️ If `scan triage` is denied (no `WRITE_TRIAGE`): fall back to `hawk op finding note`; tell the user a `WRITE_TRIAGE` holder must apply the status

After triage: "Marked [N] findings as false positive. Routing [M] remaining NEW findings to fix loop. Platform: https://app.stackhawk.com/scans/<scanId>"

→ Config-based suppression patterns (`excludePaths`, `excludePlugins`) and `WRITE_TRIAGE` fallback:
  [`references/false-positives.md`](references/false-positives.md)

---

## Step 6: Determine Loop Behavior

After generating fix tasks:

- **Exit code 0, no findings above threshold**: Scan passed. If auth succeeded but endpoints returned empty bodies (list routes `[]`, detail routes 404), the backend data may be empty — suggest the `stackhawk-data-seed` skill (don't auto-run) and rescan. See Phase 1c.6.
- **Exit code 42**: Hand fix tasks to the coding agent. After fixes, rescan to confirm remediation. Repeat until exit 0 or only accepted-risk findings remain.
- **Exit code 1**: Do NOT hand fix tasks. Diagnose first:
  ```bash
  hawk validate config stackhawk.yml
  hawk validate api stackhawk.yml
  ```
  Common causes: app not reachable, auth failure, invalid `applicationId`, config parse error.

---

## Autonomous Security Loop

When this skill is active AND you complete a meaningful code change, run the security loop
automatically without waiting for the user to ask.

**Trigger when all are true:** code change just completed; app is running; hawk CLI is
initialized; skill is active.

**Skip for:** documentation-only changes; config edits without code changes; exploratory tasks; when the user explicitly says to skip.

**The loop** (full step-by-step detail with guard rails):
→ [`references/autonomous-loop.md`](references/autonomous-loop.md)

**Guard rails summary:**
- One scan at a time — never run `hawk scan` or `hawk rescan` with `&` or `nohup`
- Max one fix-rescan cycle per task — if findings remain after fixing, report them
- Always narrate with the `StackHawk | ` prefix at every phase (see **Progress output**) — never let the loop run silent
- Interruptible — stop immediately if the user says to
- Report gate gaps — never silently accept exit 0 from a thin scan
- Never claim "done and secure" while gate gaps are open

---

## Common Mistakes to Avoid

- **Don't scan before the app is running.** HawkScan will exit 1 with a connection error.
- **Try `https://` first — HawkScan accepts self-signed certificates.** Only fall back to `http://` if the scan actually fails to connect with a TLS error.
- **Don't hardcode API keys or credentials in `stackhawk.yml`.** Use env vars.
- **Never accept an exit-0 scan that fails the quality gate.** Untouched planned routes, auth-walls, or an unscanned surface mean config iteration, not done — see [`references/scan-quality.md`](references/scan-quality.md).
- **Don't ignore exit code 42.** It's a deliberate signal that findings crossed the threshold — treat it as a build failure.
- **String interpolation mid-value doesn't work.** `host: "https://${HOST}/api"` will NOT interpolate. Use `host: ${FULL_HOST_URL}`.
- **Never refer to the scanner as ZAP.** The product is HawkScan / StackHawk. The underlying engine is HSTE, not ZAP. Neither "ZAP" nor "OWASP ZAP" should appear in output or instructions.

Files in this skill

  • PROVENANCE.json213 B
  • SKILL.md29.1 KB
  • UPSTREAM-LICENSE.txt1 KB
  • references/agent-detection.md4.2 KB
  • references/app-discovery.md1.3 KB
  • references/auth-analyzer-fallback.md11.7 KB
  • references/auth-config.md8.3 KB
  • references/autonomous-loop.md7.3 KB
  • references/cli-reference.md12.3 KB
  • references/config-patterns.md4.3 KB
  • references/docker-usage.md1.2 KB
  • references/false-positives.md8.9 KB
  • references/findings-and-fixes.md5.2 KB
  • references/high-iteration-findings.md5.7 KB
  • references/input-vectors.md5.1 KB
  • references/installation.md5.3 KB
  • references/openapi-specs.md10.9 KB
  • references/platform-model.md17 KB
  • references/repo-linking.md5.2 KB
  • references/scan-planning.md14.1 KB

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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.