Getting Started
Install Fendix and run your first scan in three commands. Covers curl, Homebrew, Docker, and builds from the official source repository, then black-box, white-box, and hybrid scans, authenticated targets, CI/CD gating, baselines, and the hosted API.
Current execution scope
- Runtime
- Prebuilt Go binaries do not require a Go compiler for basic scanning. Building from source requires Go 1.25+. Optional analyzers have their own runtime requirements; inspect coverage to confirm they actually ran.
- DAST
- URL and API probing inspect observable runtime behavior. Intrusive probes require --enable-active. An HTTP 200 response alone does not prove access to sensitive data.
- SAST
- Native static rules cover supported Go, JavaScript, Java and infrastructure patterns. Semgrep and the opt-in Python engine extend applicable checks. Language support does not imply complete framework or path coverage.
- SCA
- Go analysis uses govulncheck. Python and npm dependency scanners use supported manifests and lockfiles, including poetry.lock, Pipfile.lock and package-lock.json. Advisory queries can transmit package names and versions.
- Evidence and policy
- Correlation connects supported matching observations; not every finding has multiple sources. Strong single-source evidence can be sufficient. Severity, confidence, finding disposition and release recommendation are distinct.
- Coverage and human review
- An analyzer failure or missing required evidence can leave the release incomplete. A PASS is a result under the declared policy and coverage, not a guarantee of security or a human approval.
Benchmark tables below are historical, scoped observations. Counts and synthetic regression scores are not production precision/recall. No replacement measurements are claimed here.
Read deployment-specific data handlingQuick Start
Three commands to go from zero to a full HTML security report.
# 1. Install
curl -fsSL https://get.fendix.dev/install.sh | sh
# 2. Run your first scan
fendix scan --url https://api.example.com --format html --output report.html
# 3. Open the report
open report.htmlFendix scans the API for missing security headers, CORS misconfigurations, insecure cookie flags, authentication bypasses, sensitive data exposure, and rate limiting issues — all without sending any destructive payloads.
Installation
curl (macOS / Linux)
Downloads the latest release binary to /usr/local/bin/fendix.
curl -fsSL https://get.fendix.dev/install.sh | shHomebrew (macOS / Linux)
Install from the official Fendix-app/homebrew-fendix tap. The tap name is Fendix-app/fendix because Homebrew omits the homebrew- repository prefix.
brew tap Fendix-app/fendix
brew install fendixDocker
The Docker image works out of the box — secrets, Semgrep (if present), and dep-CVE checks all run natively in Go. The Python whitebox engine is opt-in via --python-engine if you also want auth / injection / AST checks.
docker pull fendixapp/fendix:3.4.1
docker run --rm fendixapp/fendix:3.4.1 version
docker run --rm fendixapp/fendix:3.4.1 scan --url https://api.example.comVerify the image
Verify the digest-pinned image against the official Fendix GitHub Actions identity before using it in a trusted pipeline.
IMAGE=docker.io/fendixapp/fendix
DIGEST=sha256:88783a1a032f925630bdb0977b37821add5e3381d347f91ec101401f4e98e02a
REF="$IMAGE@$DIGEST"
IDENTITY='^https://github.com/Fendix-app/Fendix/.github/workflows/release.yml@refs/heads/main$'
ISSUER='https://token.actions.githubusercontent.com'
cosign verify \
--certificate-identity-regexp "$IDENTITY" \
--certificate-oidc-issuer "$ISSUER" \
"$REF"Build from Source
Requires Go 1.25+. Python is no longer required for the default scan path as of v0.9 — it's only needed if you opt into the Python whitebox engine via --python-engine, in which case install Python 3.9+ and the deps in python/requirements.txt.
git clone https://github.com/Fendix-app/Fendix.git
cd Fendix
make build
./bin/fendix version
# Default scan path needs no Python — secrets, semgrep (if installed),
# and dep-CVE checks all run as native Go. For the
# opt-in --python-engine path (auth / injection / AST checks), install
# Python deps:
# pip install -r python/requirements.txtCurrent release: v3.4.1. The engine images build with and ship Go 1.27, so govulncheck loads any module whose go.mod requires Go 1.27 or older — the earlier ceiling was 1.25. No scanner, fingerprint or exit-code changes; the Go module floor stays 1.25. v3.4.0: a scan can no longer look complete when it wasn't. Every analyzer that can silently degrade — the endpoint discovery, the spec parser, active probes, secrets, textscan, semgrep, govulncheck, pip, npm, the Python engine and its checks, and plugins — now records once per scan whether it ran, and if not, a machine-readable reason: not applicable, disabled by a flag, a missing dependency, an unsupported target, or a failure with its cause. The report's new metadata.coverage block says whether everything the run was configured to do actually ran and names the gaps. A URL scan that finds zero endpoints now writes its report before exiting 2 instead of vanishing; --fail-on-coverage-gap and --require-analyzers turn a gap into a failing build, off by default; a transient network failure in a dependency scanner is retried once in process; SARIF, HTML and PDF show the coverage table; and the Docker image now ships a Go toolchain so govulncheck runs inside it. Finding identity, scoring and default exit codes are unchanged. v3.3.0: an upgrade no longer splits a finding you were already tracking into a closed one and a new one: reports now carry the retired identity alongside the current one, purely as a migration bridge for anything that joins findings across the v3.0 identity change. Nothing scores or filters on it, and the current identity is unchanged, so saved baselines and .fendix-ignore fingerprint: rules keep matching. The list of checks a scan ran is also honest now — it is built from what actually completed rather than what was configured, so a scanner that was unavailable is no longer named as though it had run. v3.2.0 made every blocking decision explain itself: Every blocking decision now explains itself in the report. A finding carries the decision, the policy it was made under, the evidence class that justified it, and a rule-by-rule breakdown of its confidence score — and the JSON and SARIF reports say the same thing, so "why did this fail my pipeline?" is answerable without opening Fendix. A build blocked only because confidence enforcement was switched off is labelled as such, and findings that do not block are never marked as though they did. v3.1.0 stopped findings claiming more than they proved: wildcard CORS with credentials is a misconfiguration rather than an exploit and no longer fails a build, missing rate limiting is ranked by how abusable the endpoint is, browser security headers are judged against the response they sit on, a dynamic file path is not reported as a proven traversal, obvious test fixtures stop being treated as leaks, and an unresolved import is no longer read as proof a dependency is unused. The engine ships a unified Go/JS/IaC/Java textscan SAST engine, decision reports (BLOCK / WARN / INFO with a deterministic confidence band), PDF reports and Arabic HTML, Jira / Slack / Teams integrations, diff-aware scans that run on every commit (fendix scan --code . --diff --staged --fast), a fendix hook install pre-commit gate, Proven Path taint chains exported as SARIF codeFlows, and transitive Python SCA over poetry.lock / Pipfile.lock. v3.0 changed finding identity: a finding is identified by rule, file, symbol and operation rather than partly by its line, so it survives edits above it — but a baseline saved by an older release matches nothing and must be regenerated with --save-baseline, along with any .fendix-ignore rule pinning a fingerprint: value. v2.0 CI behaviour still applies: --fail-on consults the deterministic confidence band, not severity alone — --enforce-confidence=false restores the previous mapping byte-for-byte. On the labeled synthetic accuracy corpus, fendix scores F1 = 1.000 across all detection categories. See /performance for the cold-start benchmark and /accuracy for the precision/recall scorecard.
Usage Examples
Black-box scan
Point Fendix at a live API. No source code needed. Runs all passive checks.
fendix scan --url https://api.example.comWhite-box scan
Analyze source code without making any network requests. The default v0.9 path runs the native-Go secrets scanner, dep-CVE scanners (Go via govulncheck, PyPI/npm via OSV.dev), and shells out to Semgrep if it's on PATH. AST analysis (auth/injection patterns) and spec-derived auth checks live in the Python engine — opt in with --python-engine when you want them. --spec always feeds endpoint discovery, even without --python-engine.
# Default — runs Go-native scanners
fendix scan --code ./src
# Add --spec for endpoint-discovery from an OpenAPI doc
fendix scan --code ./src --spec openapi.yaml
# Opt into the Python engine for AST + spec-derived auth checks
fendix scan --code ./src --spec openapi.yaml --python-engineHybrid scan (maximum coverage)
Black-box plus white-box, with the correlator cross-referencing both sides. Correlated findings get elevated severity, and proven-reachable correlated findings get a second bump (the "wedge" — DAST + SAST agreed AND we can prove the exploit path). The Go-native white-box scanners produce source: whitebox findings on their own; correlation works in the default path. Add --python-engine for the legacy AST + spec auth checks.
fendix scan \
--url https://api.example.com \
--code ./src \
--spec openapi.yaml \
--format html \
--output report.html
# Add --python-engine if you want the legacy AST/spec auth checks
# alongside the native Go secrets + Semgrep + dep-CVE pipeline.Authenticated scan
Provide credentials to test endpoints behind authentication. Auth credentials are always masked as [REDACTED] in output.
# Bearer token
fendix scan --url https://api.example.com --auth "Bearer eyJhbG..."
# API key with custom header
fendix scan --url https://api.example.com \
--auth "sk-live-abc123" \
--auth-type apikey \
--auth-header "X-API-Key"
# Basic auth
fendix scan --url https://api.example.com \
--auth "admin:password" \
--auth-type basicActive injection testing (opt-in)
Tests for injection (SQL/command), reflected XSS, in-band SSRF, open redirect, host-header injection, GraphQL introspection, and HTTP method tampering. Off by default — requires explicit consent.
fendix scan --url https://api.example.com --enable-activeOnly use against systems you own or have written authorization to test.
CI/CD gating
Fail the pipeline on critical or high severity findings the scan can stand behind. Since v2.0 exit code 1 needs both: a finding at or above your threshold AND a confidence band that supports it, so an uncorroborated finding warns instead of breaking the build.
fendix scan \
--url https://api.staging.example.com \
--code ./src \
--fail-on HIGH \
--format sarif \
--output results.sarif
# As of v2.0, --fail-on consults the confidence band as well as severity:
# a HIGH band blocks, MEDIUM blocks only with at least one corroborating
# signal, LOW warns. Builds that used to fail may now pass.
# --enforce-confidence=false restores the severity-only gate; a real
# credential in production code reaches HIGH on its own and still blocks.Baseline diff mode
Only report new findings compared to a previous scan. Ideal for PR workflows.
# Save a baseline
fendix scan --url https://api.example.com --save-baseline baseline.json
# Later, compare against it
fendix scan --url https://api.example.com --baseline baseline.json
# v2.0 names a dependency finding after its canonical CVE, so a baseline
# entry or a .fendix-ignore fingerprint: rule that pins one stops matching.
# Regenerate baselines saved before 2.0.Configuration
.fendix-ignore
Suppress known findings or exempt endpoints from scanning. Place as .fendix-ignore in your project root or pass via --ignore.
# Suppress by finding ID
ignore:
- id: SEC-014
reason: "Rate limiting handled at API gateway level"
until: 2026-12-01 # optional expiry date
# Suppress entire endpoint
- endpoint: GET /health
reason: "Public health check endpoint by design"
# Suppress by category on specific endpoints
- endpoint: GET /api/public/*
category: auth
reason: "Public endpoints intentionally unauthenticated"Re-render a report
Convert a saved JSON findings file to HTML or SARIF without re-scanning.
fendix report --input findings.json --format html --output report.htmlScan from the SaaS API & dashboard
Beyond the CLI, the Fendix SaaS API launches scans programmatically and aggregates them in a dashboard. Authenticate with an X-API-Key (Pro plan and up). See Integrations for pipeline-ready recipes.
# Launch a scan via the API — X-API-Key (fx_ prefix, Pro plan and up)
curl -X POST https://api.fendix.dev/api/scans \
-H "X-API-Key: $FENDIX_API_KEY" \
-H 'Content-Type: application/json' \
-d '{ "mode": "blackbox", "url": "https://api.example.com", "fail_on": "high" }'
# Workspace overview: totals, severity + category breakdowns, 8-week trend
curl "https://api.fendix.dev/api/dashboard?organization=$ORG_ID" \
-H "X-API-Key: $FENDIX_API_KEY"Self-hosted runners
A runner is an agent you host inside your network: it claims queued jobs, runs the engine against private or internal targets, and submits the report back to the dashboard. Requires the Enterprise plan's self_hosted_runners feature.
# Self-hosted runner (Enterprise): scan private/internal targets in-network
# and push results to the dashboard. Register once (org admin) → fxr_ token.
curl -X POST https://api.fendix.dev/api/runners/claim -H "X-Runner-Token: $TOKEN"
fendix scan --code /repo --format json --output report.json
curl -X POST "https://api.fendix.dev/api/runners/jobs/$SCAN_ID/result" \
-H "X-Runner-Token: $TOKEN" -H 'Content-Type: application/json' \
--data-binary @report.jsonUse the dashboard workflows
Open Scans, choose a scan, then use AI reports to generate a summary, remediation plan or fix guidance. Pro or higher and workspace AI credits are required. AI assistance does not change the scan decision. If generation is delayed, use Check status to continue polling without submitting another report.
In Settings → Integrations, select Edit / deliveries on a webhook. Update its name, events or format, and inspect its latest 50 deliveries, HTTP responses and errors. Sending a test queues an event; the delivery history confirms the outcome.
In Release approvals, search for a scan to request an exception. Use Open request link to share a specific request with an authorized reviewer. The link selects its organization workspace; existing membership and review permissions still apply.