HawkOp CLI
hawkop is the StackHawk companion CLI — a single binary for exploring your organization’s scan results, findings, audit logs, and configuration from the terminal, and for taking targeted actions on them: triaging findings, tuning per-application tech flags, and linking apps to the repositories they came from.
Where the StackHawk CLI (hawk) runs scans, hawkop operates on the results of those scans and everything else available through the StackHawk platform. It wraps the StackHawk API with human-readable tables, JSON output for scripts, response caching, and shell completions.
hawkop uses your StackHawk API key to call the same public API available to every integration. Your organization must belong to a plan with API Access enabled. Reach out to support@stackhawk.com to enable it.
When to use HawkOp
| Task | Tool |
|---|---|
| Run a DAST scan against a running application | hawk scan |
| List recent scans, apps, teams, or policies | hawkop |
| Inspect findings from a completed scan | hawkop scan get |
| Triage findings (false positive, risk accepted, comment) | hawkop scan triage |
| Tune per-app tech flags to speed up scans | hawkop app tech-flags |
| Link a StackHawk app to a code repository | hawkop repo link |
| Automate reporting or CI/CD gates from scan data | hawkop --format json |
| Query the audit log or triage history | hawkop audit list |
| Write a custom integration against the REST API | StackHawk API |
hawkop is the fastest way to explore your StackHawk data and the most script-friendly alternative to writing raw REST calls.
Features
- Full platform access — organizations, applications, scans, findings, users, teams, policies, repositories, audit log, scan configurations, OpenAPI specs, user secrets, and environments
- Rich filtering — filter scans by status, environment, or application; audit logs by date, activity type, or user
- Flexible output —
--format prettyfor interactive use,--format tablefor grep-friendly lists,--format jsonfor automation - Scan drill-down —
hawkop scan getwalks the scan → alerts → findings chain in a single command, with optional HTTP request/response evidence - Triage write surface — mark findings as
FALSE_POSITIVE/RISK_ACCEPTEDor attach comments viahawkop scan triage, single-action or bulk from a JSON/YAML file - Tech-flag tuning — read and write per-application tech flags (
hawkop app tech-flags) to speed up scans and reduce false positives - Repo ↔ app mapping — link applications to their upstream code repositories with
hawkop repo linkfor attack-surface coverage - Response caching — SQLite-backed cache in
~/.hawkop/cache/makes repeated queries snappy; bypass with--no-cache - Parallel pagination — large datasets fetch in parallel after the first page
- Reactive rate limiting — only engages after the API returns
429, so small queries stay fast - Profiles — switch between orgs, users, or API keys with
hawkop profile/-P <name> - Shell completions — static and dynamic completions for Bash, Zsh, Fish, and PowerShell
- Cross-platform — native binaries for Linux, macOS, and Windows on x86_64 and ARM64
Installation
All hawkop artifacts are published to download.stackhawk.com. The current version is always available as plain text at /hawkop/latest-version.txt.
For a streamlined installer experience (auto-detects your platform and picks the right artifact), see the HawkOp Downloads page.
Install with Homebrew (macOS / Linux)
brew tap stackhawk/cli
brew install hawkop
The Homebrew tap is hosted at stackhawk/homebrew-cli and is updated automatically on every hawkop release.
Install with PKG (macOS)
Download and double-click the signed .pkg for the universal macOS build:
VERSION=$(curl -s https://download.stackhawk.com/hawkop/latest-version.txt)
curl -L "https://download.stackhawk.com/hawkop/pkg/hawkop-v${VERSION}-macos-universal.pkg" -o hawkop.pkg
open hawkop.pkg
Install with MSI (Windows)
Download the signed Windows installer:
$Version = (Invoke-WebRequest https://download.stackhawk.com/hawkop/latest-version.txt).Content.Trim()
Invoke-WebRequest "https://download.stackhawk.com/hawkop/msi/hawkop-v$Version-windows-x64.msi" -OutFile hawkop.msi
Start-Process msiexec.exe -ArgumentList "/i hawkop.msi /passive" -Wait
Install from a release archive
Every release publishes signed per-target tarballs under https://download.stackhawk.com/hawkop/cli/:
| Platform | Architecture | Artifact |
|---|---|---|
| macOS | Intel | hawkop-v{VERSION}-x86_64-apple-darwin.tar.gz |
| macOS | Apple Silicon | hawkop-v{VERSION}-aarch64-apple-darwin.tar.gz |
| Linux | x86_64 | hawkop-v{VERSION}-x86_64-unknown-linux-gnu.tar.gz |
| Linux | ARM64 | hawkop-v{VERSION}-aarch64-unknown-linux-gnu.tar.gz |
| Windows | x86_64 | hawkop-v{VERSION}-x86_64-pc-windows-msvc.zip |
Each archive has a matching .sha256 checksum file alongside it at the same path. Example (macOS Apple Silicon):
VERSION=$(curl -s https://download.stackhawk.com/hawkop/latest-version.txt)
TARGET=aarch64-apple-darwin
ARCHIVE="hawkop-v${VERSION}-${TARGET}.tar.gz"
BASE="https://download.stackhawk.com/hawkop/cli"
curl -L "${BASE}/${ARCHIVE}" -o "${ARCHIVE}"
curl -L "${BASE}/${ARCHIVE}.sha256" -o "${ARCHIVE}.sha256"
# Verify
shasum -a 256 -c "${ARCHIVE}.sha256"
# Extract and install
tar -xzf "${ARCHIVE}"
sudo mv hawkop /usr/local/bin/
hawkop --version
QuickStart
1. Initialize
hawkop init
This prompts for your StackHawk API key, authenticates, captures your default organization, and writes ~/.hawkop/config.yaml.
hawkop init is interactive by default. For headless setup (CI/CD), set HAWKOP_API_KEY in the environment and skip init — hawkop will read the key directly.
2. Verify setup
hawkop status
Reports the active profile, organization, API host, and whether the JWT is currently valid.
3. Explore your data
hawkop org list # Organizations you belong to
hawkop app list # Applications in the active org
hawkop scan list # Most recent scans across all apps
hawkop scan get # Latest scan with alerts breakdown
hawkop scan get <ID> # Specific scan with findings
Usage
Global options
These flags apply to every command:
| Flag | Env var | Description |
|---|---|---|
--format <pretty|table|json> | HAWKOP_FORMAT | Output format. pretty for humans, table for one row per entry, json for scripts. Defaults to pretty. |
--org <ORG_ID> | HAWKOP_ORG_ID | Override the default organization. |
--config <PATH> | HAWKOP_CONFIG | Override config file location. |
-P, --profile <NAME> | HAWKOP_PROFILE | Switch to a named profile (different org, user, or API key). |
--debug | HAWKOP_DEBUG | Enable debug logging to stderr. |
--no-cache | HAWKOP_NO_CACHE | Bypass the local cache and fetch fresh data. |
Precedence: command-line flags > environment variables > config file > defaults.
Exit codes and output streams
- Data goes to stdout; progress, prompts, and errors go to stderr — pipes and redirects stay clean.
hawkoprespectsNO_COLOR,TERM=dumb, and--no-colorfor plain output.- Non-zero exit codes indicate failure; scripts can branch on exit status without parsing text.
Commands
The full command surface. Use hawkop <command> --help for detailed flags and examples on any subcommand.
hawkop init
Interactive setup. Prompts for API key, authenticates, and writes ~/.hawkop/config.yaml.
hawkop status
Show the active profile, API host, organization, JWT validity, cache size, and the commands a user would run next.
hawkop version
Print the hawkop version.
hawkop org
Work with organizations your user belongs to.
hawkop org list # List organizations
hawkop org set <ORG_ID> # Set the default organization
hawkop org get # Show the current default organization
hawkop app
hawkop app list # List applications in the active org
hawkop app list --type cloud # Filter by application type (cloud, standard)
hawkop app list -n 50 --sort-by name
hawkop app create --name <NAME> --env <ENV> # Create an application
hawkop app get <APP_ID> # Application detail
hawkop app update <APP_ID> --name <NEW_NAME> # Rename
hawkop app delete <APP_ID> # Delete (requires confirmation)
hawkop app tech-flags
Tech flags are per-application toggles that control which technology-specific vulnerability checks StackHawk runs (e.g., Language.Java.Spring, Db.PostgreSQL, OS.Linux). Disabling unused technologies speeds up scans and reduces false positives. Defaults are all enabled.
hawkop app tech-flags get --app <NAME_OR_ID>
hawkop app tech-flags set --app <NAME_OR_ID> KEY=VALUE [KEY=VALUE ...] [--dry-run]
hawkop app tech-flags enable-all --app <NAME_OR_ID> [--yes] [--dry-run]
hawkop app tech-flags disable-all --app <NAME_OR_ID> [--yes] [--dry-run]
KEY=VALUE accepts case-insensitive true|1|on|yes or false|0|off|no. enable-all and disable-all prompt for confirmation; pass --yes to skip the prompt or --dry-run to preview the change without writing.
# See current flags grouped by namespace
hawkop app tech-flags get --app my-api
# Disable two flags
hawkop app tech-flags set --app my-api Db.MySQL=false Language.Python=false
# Wipe everything and selectively re-enable a few
hawkop app tech-flags disable-all --app my-api --yes
hawkop app tech-flags set --app my-api Language.Java=true OS.Linux=true
hawkop scan
hawkop scan list # Recent scans, paginated
hawkop scan list --status complete --env production
hawkop scan list --app <APP_ID> # Scans for a single application
hawkop scan get # Latest scan: overview + alerts
hawkop scan get <SCAN_ID> # A specific scan
hawkop scan get --app myapp # Latest scan for an app by name
hawkop scan get <SCAN_ID> --plugin-id 40012 # Alert detail
hawkop scan get <SCAN_ID> --uri-id <URI_ID> --message # Finding + HTTP request/response
hawkop scan get --detail full --format json # All findings, remediation, evidence
hawkop scan get walks the scan → alerts → findings chain in a single invocation so you don’t have to stitch three API calls together yourself. --detail full returns every finding with HTTP messages and remediation advice — ideal for feeding an AI agent.
hawkop scan triage
Mark scan findings as FALSE_POSITIVE or RISK_ACCEPTED, or attach a comment via ADD_COMMENT, in batches of up to 100 per call. Triage rules apply to future scans automatically. Each environment has its own finding hashes — triage is per-environment.
hawkop scan triage <selectors> <input-mode> [--dry-run]
Selectors (mutually exclusive):
--scan <SCAN_ID> agent shortcut: derives app+env
| --app <NAME_OR_ID> --env <NAME_OR_ID> explicit form
Input modes (mutually exclusive):
--hash <SHA> --status STATUS [--note "..."] single action
| --from-file <PATH> JSON or YAML array
| --from-file - read from stdin
STATUS is case-insensitive: FALSE_POSITIVE | RISK_ACCEPTED | ADD_COMMENT (kebab and snake variants accepted). ADD_COMMENT requires --note. The API returns 200 even on partial failures — hawkop renders per-action ✓/✗, prints a summary, and exits non-zero if anything failed so scripts can detect partial success.
# Triage one finding from a known scan (typical agent path)
hawkop scan triage --scan abc123 --hash <sha> --status false-positive --note "XSS test fixture"
# Comment-only when an agent can't auto-fix
hawkop scan triage --scan abc123 --hash <sha> --status add-comment --note "Tracked in JIRA-456"
# Bulk from a YAML file
hawkop scan triage --app my-api --env Production --from-file triage.yaml
# Bulk from stdin
echo '[{"findingHash":"abc","status":"FALSE_POSITIVE","note":"..."}]' \
| hawkop scan triage --scan abc123 --from-file -
# Preview without writing
hawkop scan triage --scan abc123 --hash <sha> --status false-positive --dry-run
The file format is a flat array (no top-level wrapper):
- findingHash: a1b2c3...
status: FALSE_POSITIVE
note: "Test fixture, not real injection"
- findingHash: d4e5f6...
status: ADD_COMMENT
note: "Tracked in JIRA-456 — fix scheduled for v0.9"
Finding hashes are SHA-256 identifiers — copy them from hawkop scan get --detail full --format json | jq '.findings[].findingHash' or from the equivalent fields surfaced in alert/path output.
hawkop run
Start, stop, and check the status of hosted scans (scans executed by the StackHawk platform against cloud applications).
hawkop run start <APP_ID> --env <ENV>
hawkop run status <SCAN_ID>
hawkop run stop <SCAN_ID>
hawkop user, hawkop team
hawkop user list # Organization members
hawkop team list # Teams in the organization
hawkop policy
hawkop policy list # Custom and system scan policies
hawkop repo
hawkop repo list # Repositories in the attack surface
hawkop repo link # Link an app to a repo (additive, preserves existing mappings)
hawkop repo set-apps # Replace all app mappings for a repo (destructive)
hawkop repo link is the everyday verb for tying a StackHawk application to its upstream code repository so attack-surface coverage and findings can be traced back to source. It is additive — existing mappings on the repo are preserved.
# Link an existing application by ID
hawkop repo link --repo-id <UUID> --app-id <APP_UUID>
# Create a new app and link it in one step
hawkop repo link --repo-id <UUID> --app-name "my-api"
# Resolve the repo by name
hawkop repo link --repo "kaakaww/my-api" --app-id <APP_UUID>
hawkop repo set-apps is the destructive counterpart — it replaces the repository’s entire set of app mappings with the list you provide. Use it when you intentionally want to clear what’s there. Prompts for confirmation by default; pass --yes to skip and --dry-run to preview.
hawkop repo set-apps --repo-id <UUID> --app-ids <ID1>,<ID2> --yes
hawkop oas
hawkop oas list # Hosted OpenAPI specifications
hawkop config
List stored scan configurations (the stackhawk.yml uploaded to the platform per application/environment).
hawkop config list
hawkop secret
List user secret names (values are never returned by the API).
hawkop secret list
hawkop audit
Query the organization audit log with filters, date ranges, and relative dates.
hawkop audit list --since 7d
hawkop audit list --type SCAN_STARTED,SCAN_COMPLETED --since 30d
hawkop audit list --user "Jane Smith" --email jane@example.com
hawkop audit list --since 2025-01-01 --until 2025-01-31
hawkop env
Manage application environments.
hawkop env list --app <APP_ID> # Environments for an app
hawkop env config --app <APP_ID> --env prod # Default stackhawk.yml for an environment
hawkop env create --app <APP_ID> --env staging --host https://staging.example.com
hawkop env delete --app <APP_ID> --env old-env
hawkop cache
Inspect and manage the SQLite response cache.
hawkop cache status # Stats: hit rate, size, entry count
hawkop cache clear # Clear all cached responses
hawkop cache path # Print the cache database path
hawkop profile
Switch between orgs, users, or API keys without rewriting your config.
hawkop profile list
hawkop profile add <NAME> # Interactive profile creation
hawkop profile set <NAME> # Make it the active profile
hawkop profile remove <NAME>
Use a profile for a single command without switching:
hawkop --profile work scan list
hawkop -P personal app list
hawkop completion
Generate static shell completions.
hawkop completion bash # bash
hawkop completion zsh # zsh
hawkop completion fish # fish
hawkop completion powershell # PowerShell
See Shell completions for installation snippets.
Common usage patterns
Filter scans
hawkop scan list --status complete # Only completed scans
hawkop scan list --env production # Only production
hawkop scan list --app <APP_ID> -n 50 # Last 50 for one app
hawkop scan list --env staging --status failed # Combine filters
Query the audit log
hawkop audit list --since 7d
hawkop audit list --type SCAN_STARTED,SCAN_COMPLETED --since 30d
hawkop audit list --since 2025-01-01 --until 2025-02-01
Pipe to jq for automation
# App names only
hawkop app list --format json | jq -r '.data[].name'
# Scans for production with a high finding
hawkop scan list --env production --format json \
| jq '.data[] | select(.highAlertCount > 0) | {id, applicationId, highAlertCount}'
# Dump a scan and all findings for an AI agent
hawkop scan get <SCAN_ID> --detail full --format json > scan.json
Switch organizations temporarily
hawkop --org <OTHER_ORG_ID> scan list # One-shot override
hawkop -P customer-a scan list # Named profile
Agent-driven triage
A typical workflow for an AI agent reviewing findings during automated remediation:
# 1. Fetch full findings for a scan (the agent already knows the scan ID)
hawkop scan get <SCAN_ID> --detail full --format json > findings.json
# 2. The agent inspects each finding. For ones it has verified are
# false positives, it triages with a note explaining why.
hawkop scan triage \
--scan <SCAN_ID> \
--hash <FINDING_HASH> \
--status false-positive \
--note "Test fixture endpoint; not exposed in production."
# 3. For a finding the agent cannot auto-fix, it adds a comment so
# a human reviewer has context.
hawkop scan triage \
--scan <SCAN_ID> \
--hash <FINDING_HASH> \
--status add-comment \
--note "Cannot auto-fix; tracked in JIRA-456."
The --scan <SCAN_ID> shortcut derives both the application and environment from the scan, so the agent doesn’t need to look those up separately.
Configuration
Config file
hawkop stores configuration at ~/.hawkop/config.yaml. Typical contents:
api_key: hawk.abc123...
org_id: 00000000-0000-0000-0000-000000000000
jwt:
token: eyJhbGci...
expires_at: 2026-01-15T12:00:00Z
preferences:
page_size: 1000
profiles:
work:
api_key: hawk.def456...
org_id: 11111111-1111-1111-1111-111111111111
Do not commit this file. It contains your API key and a valid JWT. On Unix, hawkop sets the file permissions to 0600.
Environment variables
| Variable | Purpose |
|---|---|
HAWKOP_API_KEY | API key — useful in CI/CD where no config file exists |
HAWKOP_ORG_ID | Default organization |
HAWKOP_FORMAT | Default output format (pretty, table, or json) |
HAWKOP_CONFIG | Alternate config file path |
HAWKOP_PROFILE | Active profile |
HAWKOP_DEBUG | Enable debug logging |
HAWKOP_NO_CACHE | Disable response caching |
CI/CD setup
export HAWKOP_API_KEY=hawk.xxxxxxxxxxxx
export HAWKOP_ORG_ID=00000000-0000-0000-0000-000000000000
export HAWKOP_FORMAT=json
hawkop scan list --env production \
| jq '.data[] | select(.highAlertCount > 0)' \
| tee high-findings.json
HAWKOP_API_KEY is read directly — no interactive init required.
Caching
hawkop caches API responses in a local SQLite database at ~/.hawkop/cache/hawkop_cache.db. Cache TTLs are tuned per endpoint:
- Short-lived data (scan lists, audit log) cached for seconds to a minute
- Stable data (apps, teams, policies) cached for minutes
- Immutable data (finding details for a completed scan) cached longer
Bypass the cache per-command with --no-cache, or globally with HAWKOP_NO_CACHE=1.
hawkop cache status # Stats
hawkop cache clear # Clear everything
hawkop cache path # Where the db lives
Shell completions
Static completions
Generate once and install into your shell’s completion directory:
hawkop completion bash > ~/.local/share/bash-completion/completions/hawkop hawkop completion zsh > ~/.zfunc/_hawkop
# Ensure ~/.zfunc is on fpath and `autoload -U compinit && compinit` runs in .zshrc hawkop completion fish > ~/.config/fish/completions/hawkop.fish hawkop completion powershell >> $PROFILE Dynamic completions
hawkop also provides API-backed dynamic completions for values like organization IDs, application IDs, scan IDs, and environment names. These activate automatically once static completions are installed — start typing an --org value and press TAB to see live suggestions.
Troubleshooting
hawkop status reports no API key
Run hawkop init (interactive) or export HAWKOP_API_KEY. Create an API key at Settings → API Keys.
Commands return empty lists
Confirm the active org with hawkop org get. If it isn’t the one you expect, run hawkop org set <ORG_ID> or pass --org <ORG_ID> per command.
Stale data in tables
Response caching can return slightly old data. Pass --no-cache to force a fresh fetch, or run hawkop cache clear.
Rate limited (429) during large reports
hawkop automatically backs off and retries when the API returns 429. If you’re consistently hitting it, break the query into smaller windows (e.g. with --since on the audit log).
Resources
- Downloads: download.stackhawk.com/hawkop/
- Homebrew tap: stackhawk/homebrew-cli
- API reference: apidocs.stackhawk.com
- Report a bug: support@stackhawk.com
Need Help?
If you encounter an issue you cannot solve with this documentation, reach out to StackHawk Support.