---
description: >
  HawkScan false positives guide: identifying false positives, deciding fix vs suppress, excludePaths and failureThreshold config, excluding scan plugins, reporting accepted risk.
globs:
alwaysApply: false
---
# False Positives and Accepted Risk

## Identifying False Positives

Not every finding from a DAST scan is a real vulnerability. Some common false positive
scenarios:

- **Health check or status endpoints** that intentionally return server info (e.g.,
  `/health`, `/actuator/info`) may trigger "Information Disclosure" findings
- **CORS headers** set intentionally permissive for public APIs
- **Deliberately open endpoints** (public API docs, login pages) flagged for missing
  authentication
- **Security headers on non-HTML responses** — CSP, X-Frame-Options findings on JSON
  API endpoints that never serve HTML
- **Rate limiting findings** on endpoints that are already behind an API gateway
  enforcing rate limits

## How to Decide: Fix or Suppress?

| Signal | Action |
|--------|--------|
| The finding describes real user-input handling with no sanitization | **Fix it** |
| The finding is on a test/mock endpoint not present in production | **Suppress** — exclude the path |
| The finding is on an intentionally open endpoint (health, docs) | **Suppress** — exclude the path |
| The finding is a header issue on a non-HTML API response | **Suppress** — exclude the path or accept the risk |
| You're unsure | **Fix it** — false negatives are worse than false positives |

## Suppression via Config

### Exclude specific paths from scanning

The scanner is pinned to the `host:` value in `stackhawk.yml` and will not
traverse to other hosts. You do **not** need to add external domains or CDN
URLs to `excludePaths` — the scanner won't follow them.

Use `excludePaths` for same-host paths that generate noise without security
value: static assets (images, CSS, JavaScript bundles), health endpoints,
API docs, and similar paths that are either not user-controllable or not
relevant to security testing.

```yaml
app:
  excludePaths:
    - /health
    - /actuator/info
    - /swagger-ui
    - /api-docs
    - /static
    - /assets
```

### Control which severity triggers exit code 42

`failureThreshold` belongs under `hawk:` — **never under `app:`**.

```yaml
hawk:
  failureThreshold: MEDIUM   # LOW | MEDIUM | HIGH
```

The scan always reports all findings regardless of this setting. `failureThreshold`
only controls the exit code: the scan exits `42` (triggering the fix loop) when a
finding at or above the threshold is found; otherwise it exits `0`.

Use this to gate CI pipelines by severity — for example, allow Low findings to pass
without triggering the fix loop while still recording them in the platform.

### Exclude specific scan plugins

If a specific check consistently produces false positives for your stack:

```yaml
hawk:
  scan:
    excludePlugins:
      - 10096  # Timestamp Disclosure (common false positive on API timestamps)
```

Use this sparingly. Prefer path exclusions over disabling entire plugins.

## Triaging via the API

Use `hawkop scan triage` to record false-positive decisions on the platform.
This is the preferred action over config suppression when the finding is a true
false positive — it creates an auditable, human-reviewable record.

### When to use API triage vs. config suppression

| Scenario | Action |
|----------|--------|
| Scanner is definitively wrong about this endpoint | **API triage** → `false-positive` with note |
| Finding is real but uncertain — needs more review | **API triage** → `add-comment` with context |
| Finding is noisy but not clearly wrong | **Fix it** — when in doubt, fix |

### Single finding

```bash
hawkop scan triage \
  --scan <SCAN_UUID> \
  --hash <FINDING_HASH> \
  --status false-positive \
  --note "<reason — explain specifically why the scanner is wrong>"
```

Example notes:
- `"CSP finding on JSON endpoint /api/health which never serves HTML; header inapplicable"`
- `"CORS wildcard on public read-only metrics API; no auth, no sensitive data"`
- `"Rate-limit finding on /api/events; rate limiting enforced at API gateway layer"`

### Bulk (multiple findings in one scan)

Write a `triage.yaml`:
```yaml
- finding_hash: "sha256hash1"
  status: FALSE_POSITIVE
  note: "Health endpoint — intentional server info exposure for monitoring"
- finding_hash: "sha256hash2"
  status: FALSE_POSITIVE
  note: "CORS permissive by design; public read-only API"
```

Then apply:
```bash
hawkop scan triage --scan <SCAN_UUID> --from-file triage.yaml
```

JSON format is also accepted (leading `[` is auto-detected). Max 100 actions per call — split into batches if needed.

### Agent rules for API triage

- ✅ Mark `FALSE_POSITIVE` autonomously — note must explain clearly why
- ✅ Use `ADD_COMMENT` to annotate without changing status
- ❌ **Never mark `RISK_ACCEPTED`** — human decision only
- ❌ **Never mark `ASSIGNED`** — human decision only
- ❌ Never suppress a finding by changing code to hide it from the scanner

```bash
# ADD_COMMENT example — for findings under review but not yet confirmed FP
hawkop scan triage \
  --scan <SCAN_UUID> \
  --hash <FINDING_HASH> \
  --status add-comment \
  --note "Reviewing with team; suspected false positive on /actuator/info"
```

### How to get the finding hash

The finding hash (`--hash`) comes from the scan JSON output:
```bash
hawk scan --json-output | jq '.findings[].hash'
```

Or from `hawkop scan get`:
```bash
hawkop scan get --app <APP_NAME> --detail full --format json | jq '.data.findings[].hash'
```

The scan UUID (`--scan`) comes from:
```bash
hawk scan --json-output | jq -r '.scan.id'
```

## Reporting Accepted Risk

When you encounter a finding that is a known false positive:

1. **Do not "fix" intentional behavior.** Changing a deliberately open health endpoint
   to require auth will break monitoring.
2. **Triage via the API** using `hawkop scan triage` (see section above) so the decision
   is recorded and auditable.
3. **Report it clearly:** "Finding X on path Y is a false positive because [reason].
   Marked via API triage with note: [note]."

## When in Doubt

If you cannot determine whether a finding is a false positive:
- **Fix it.** A false negative (missing a real vulnerability) is far worse than
  spending time fixing a false positive.
- Flag it in your report: "Fixed [finding] — if this was intentional behavior,
  the change can be reverted and the path added to excludePaths."
