Run with npx
No global install needed. Run directly from your project root. FortifAI auto-discovers your config file.
npx fortifai scanRun adversarial security scans against your AI agent endpoints from the terminal or CI pipeline. No agents replaced, no data forwarded to secondary models.
No global install required. FortifAI runs via npx and auto-discovers your config.
No global install needed. Run directly from your project root. FortifAI auto-discovers your config file.
npx fortifai scanLink your CLI to your dashboard account. The auth command writes your API key into your config file.
npx fortifai authDefine your agent endpoints in a config file. Supports TypeScript, JavaScript, YAML, and YML.
fortifai.config.tsfortifai.config.ts — minimal example
export default {
agents: [
{
name: "customer-support-agent",
endpoint: "http://localhost:3000/api/chat",
method: "POST",
inputField: "message",
headers: {
"Content-Type": "application/json",
},
},
],
scan: {
concurrency: 5,
rateLimitPerSecond: 5,
},
};Supported formats: fortifai.config.ts, fortifai.config.js, fortifai.config.yaml, fortifai.config.yml
Run adversarial payloads against configured AI agent endpoints.
npx fortifai scan [options]
# with custom config directory
npx fortifai scan --config ./my-project
# custom output and rate limit
npx fortifai scan --out ./reports --rate-limit 10
# skip evaluation (raw results only)
npx fortifai scan --no-eval| Flag | Default | Description |
|---|---|---|
| --config <path> | cwd | Path to the working directory containing your fortifai config file. |
| --out <dir> | .fortifai | Output directory where scan-report.json and the event log are written. |
| --concurrency <number> | 5 | Maximum number of in-flight requests at any point in time. |
| --rate-limit <number> | 5 | Maximum request starts per second. Set to 0 to disable throttling. |
| --no-eval | — | Skip @fortifai/core evaluation and emit raw attack results only. |
| -h, --help | — | Display help text and exit. |
Authenticate the CLI with your FortifAI API key.
# interactive prompt
npx fortifai auth
# non-interactive (CI-friendly)
npx fortifai auth --api-key fai_your_key_here| Flag | Default | Description |
|---|---|---|
| --api-key <key> | — | Provide the API key directly and bypass the interactive prompt. |
| --config <path> | cwd | Working directory where the CLI searches for an existing config file. |
fortifai.config.js in the current directory. API keys must start with fai_.All config options with types, defaults, and descriptions.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Human-readable identifier for this agent target. |
| endpoint | string | yes | Full URL of the agent endpoint under test. |
| method | string | no | HTTP method for requests. Defaults to "POST". |
| inputField | string | yes | Body key that receives the adversarial payload. |
| headers | object | no | Request headers forwarded with every attack request. |
| additionalParams | object | no | Extra body fields merged alongside the payload. |
| Field | Type | Required | Description |
|---|---|---|---|
| scan.concurrency | integer ≥ 1 | no | Max in-flight requests. Overridden by --concurrency. |
| scan.rateLimitPerSecond | number ≥ 0 | no | Max request starts per second. 0 disables throttling. Overridden by --rate-limit. |
| apiKey | string | no | Your FortifAI API key (format: "fai_…"). Written automatically by fortifai auth. |
export default {
apiKey: "fai_your_key_here", // written by `fortifai auth`
agents: [
{
name: "customer-support-agent",
endpoint: "http://localhost:3000/api/chat",
method: "POST",
inputField: "message",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer <token>",
},
additionalParams: {
userId: "test-user-001",
},
},
{
name: "rag-search-agent",
endpoint: "http://localhost:4000/search",
method: "POST",
inputField: "query",
},
],
scan: {
concurrency: 10, // max parallel requests
rateLimitPerSecond: 8, // throttle to 8 starts/sec
},
};apiKey: "fai_your_key_here"
agents:
- name: customer-support-agent
endpoint: http://localhost:3000/api/chat
method: POST
inputField: message
headers:
Content-Type: application/json
scan:
concurrency: 5
rateLimitPerSecond: 5Every scan writes two files to .fortifai/ by default.
Structured report (schema v2.0.0) with execution metadata, request outcomes, latency percentiles, KPIs, findings by severity and rule, and a timeline of events.
JSON Lines stream of scan lifecycle events. Each line is a structured log entry with sequence number, timestamp, level, event type, message, and data payload.
{
"schemaVersion": "2.0.0",
"scanId": "scan_1772724227522",
"timestamp": "2026-03-05T15:25:44.826Z",
"scanWindow": {
"startedAt": "2026-03-05T15:23:47.522Z",
"completedAt": "2026-03-05T15:25:44.824Z",
"durationMs": 117302
},
"execution": {
"agentsConfigured": 1,
"payloadsLoaded": 158,
"totalAttacks": 158,
"concurrency": 5,
"rateLimitPerSecond": 5,
"evaluationEnabled": true
},
"summary": {
"findings": { "CRITICAL": 0, "HIGH": 2, "MEDIUM": 4, "LOW": 7 },
"riskScore": 62,
"requestOutcomes": {
"total": 158,
"successful": 147,
"timedOut": 11,
"http2xx": 76
},
"latency": {
"minMs": 1, "maxMs": 10014,
"avgMs": 2481, "p50Ms": 394, "p95Ms": 10006
}
},
"kpis": {
"successRatePct": 92.83,
"timeoutRatePct": 7.17,
"avgLatencyMs": 2481
},
"findings": {
"totalSignals": 13,
"bySeverity": { "HIGH": 2, "MEDIUM": 4, "LOW": 7 },
"byRule": [...],
"byTag": [...]
},
"artifacts": {
"eventLogPath": ".fortifai/scan_...-events.log.jsonl"
}
}{"sequence":1,"timestamp":"...","level":"INFO","event":"scan.started","message":"Scan started","data":{"scanId":"scan_..."}}
{"sequence":2,"timestamp":"...","level":"INFO","event":"config.loaded","message":"Configuration loaded","data":{"agents":1}}
{"sequence":3,"timestamp":"...","level":"INFO","event":"payloads.loaded","message":"Payload campaigns loaded","data":{"payloads":158}}
{"sequence":4,"timestamp":"...","level":"WARN","event":"execution.anomaly","message":"Request anomaly detected","data":{"payloadId":"PI-001","status":502}}
{"sequence":5,"timestamp":"...","level":"INFO","event":"scan.completed","message":"Scan completed successfully","data":{"durationMs":117302}}Two independent controls prevent upstream API overload. Both can be set in config or overridden at the CLI level.
Limits how many requests are active simultaneously. Setting this lower reduces parallel load on your agent service.
scan.concurrency--concurrency <number>5Controls how quickly new requests are initiated each second, even if concurrency slots are available. Set to 0 to disable.
scan.rateLimitPerSecond--rate-limit <number>5Run FortifAI as a pipeline step to gate deployments on security findings.
name: FortifAI Security Scan
on:
push:
branches: [main]
pull_request:
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start agent (example)
run: npm start &
# wait for your agent to be ready before scanning
- name: Authenticate FortifAI CLI
run: npx fortifai auth --api-key ${{ secrets.FORTIFAI_API_KEY }}
- name: Run security scan
run: npx fortifai scan --out ./security-reports
- name: Upload scan report
uses: actions/upload-artifact@v4
with:
name: fortifai-report
path: ./security-reports/Add FORTIFAI_API_KEY to your repository secrets. The scan uploads automatically to your dashboard when an API key is present.
Use --api-key flag in CI to skip the interactive prompt.
--api-key $FORTIFAI_KEYWrite reports to a known artifact directory for upload.
--out ./security-reportsIncrease concurrency and rate limit in non-prod environments.
--concurrency 20 --rate-limit 20FortifAI tests any HTTP-accessible agent endpoint regardless of the framework.
Sign up to get your API key, then run your first scan in under a minute.