Complete command-line interface reference for APILeak v0.2.0 - Enterprise API security testing tool.
- Global Options
- Commands Overview
- Directory Fuzzing (
dir)- Discovery Control Options
- Proxy Options
- Discovery Robustness Options
- Seed Inputs and Extensions
- Request Context (Headers, Cookies, Auth)
- Response Matchers and Filters
- Method Enumeration and GraphQL
- Per-Request Resilience
- Transport and TLS
- Secret and Leak Detection
- Machine-Readable Output
- Path and Status Scope (Storage-Time Selection)
- Recursion Scope
- Hit Confirmation
- Checkpoint and Resume
- Discovery Triage Options
- Discovery-to-Scan Integration (Batch Scan Scope)
- Status Code Filtering
- Examples
- Rate Limiting and User-Agent in Discovery and Triage
- Parameter Fuzzing (
par) - Security Scan (
scan) - OWASP Module Commands (
owasp) - JWT Utilities
- Proxy Integration
- Environment Variables
- Exit Codes
- Examples
These options are available for all commands:
| Option | Description | Default |
|---|---|---|
--no-banner |
Suppress banner output | false |
--help |
Show help message and exit | - |
APILeak provides the following main commands:
| Command | Purpose | Use Case |
|---|---|---|
dir |
Directory/endpoint fuzzing | Discover hidden endpoints and directories |
par |
Parameter fuzzing | Find hidden parameters in API endpoints |
scan |
Orchestrated OWASP scan (primary) | Runs discovery + all registered OWASP modules and drives the CI gate |
owasp |
OWASP module group | List modules, or run exactly one OWASP module in isolation (owasp <key>) |
jwt |
JWT security utilities | JWT token manipulation and security testing |
Deprecation.
fullandmainare deprecated, hidden aliases ofscan. They still work and forward toscan(printing a one-line deprecation notice to stderr), but you should migrate scripts toscan. Module selection through the alias also migrates:full --modules bola→apileaks owasp bola.
APILeak provides comprehensive help at multiple levels:
# Main help - shows all commands and global options
python apileaks.py --help
# Command-specific help - shows all options for a specific command
python apileaks.py scan --help
python apileaks.py owasp --help
python apileaks.py dir --help
python apileaks.py par --help
# JWT utilities help
python apileaks.py jwt --help
python apileaks.py jwt decode --help
python apileaks.py jwt encode --helpDiscover hidden API endpoints and administrative interfaces.
Purpose. The dir command performs directory and endpoint fuzzing against a target: it sends candidate paths (from wordlists and/or imported API specs), classifies each discovered endpoint, and optionally recurses into promising paths. On top of raw discovery it layers an opt-in triage workflow (status grouping, session persistence, exports, an interactive table) and can feed discovered endpoints straight into an OWASP scan.
Option groups at a glance:
| Group | What it controls |
|---|---|
| Discovery Control | Recursion depth, request budget, and concurrency |
| Proxy | Routing traffic through an intercepting proxy |
| Discovery Robustness | Seeds/extensions, request context, response matchers/filters, method/GraphQL probing, resilience, TLS, secret detection, machine output, storage-time scope, recursion scope, hit confirmation, checkpoint/resume |
| Discovery Triage | Sessions, exports, and the interactive table |
| Discovery-to-Scan Integration | Batch-scanning discovered endpoints |
| Status Code Filtering | How --status-code is parsed in triage mode |
| Rate Limiting and User-Agent | Pacing and identifying discovery requests |
python apileaks.py dir [OPTIONS]| Option | Description | Example |
|---|---|---|
--target, -t |
Target URL to scan | --target https://api.example.com |
| Option | Description | Default | Example |
|---|---|---|---|
--wordlist, -w |
Wordlist file for directory fuzzing | wordlists/endpoints.txt |
--wordlist custom_endpoints.txt |
--output, -o |
Output filename for reports | Auto-generated | --output my-scan |
--log-level |
Logging level | WARNING |
--log-level DEBUG |
--log-file |
Log file path | Console only | --log-file scan.log |
--json-logs |
Output logs in JSON format | false |
--json-logs |
--rate-limit |
Requests per second limit | 10 |
--rate-limit 5 |
--methods |
HTTP methods to test | GET,POST,PUT,DELETE,PATCH |
--methods GET,POST |
--jwt |
JWT token for authentication | - | --jwt eyJ0eXAi... |
--response |
Filter by response codes | All codes | --response 200,301,404 |
--status-code |
Filter displayed results by status code or status class | All codes | --status-code 2xx |
| Option | Description | Example |
|---|---|---|
--user-agent-random |
Use random User-Agent headers | --user-agent-random |
--user-agent-custom |
Custom User-Agent string | --user-agent-custom "MyScanner/1.0" |
--user-agent-file |
File with User-Agent strings | --user-agent-file agents.txt |
| Option | Description | Default | Example |
|---|---|---|---|
--detect-framework, --df |
Enable framework detection | false |
--detect-framework |
--fuzz-versions, --fv |
Enable API version fuzzing | false |
--fuzz-versions |
These flags tune recursive discovery so you can trade breadth for speed. They keep recursion agile: stay shallow and fast for a quick sweep, or go deep and thorough when you need full coverage — always bounded by the request budget and catch-all detection.
| Option | Description | Default | Example |
|---|---|---|---|
--depth |
Max recursion depth for discovery (0 = no recursion, depth-0 pass only) |
3 (see precedence below) |
--depth 5 |
--recursive / --no-recursive |
Enable or disable recursive discovery | enabled | --no-recursive |
--max-requests |
Global request budget for discovery | unbounded | --max-requests 5000 |
--concurrency |
Max concurrent in-flight discovery requests | 50 |
--concurrency 100 |
Depth precedence. The effective recursion depth is resolved as: explicit CLI --depth > the APILEAK_MAX_DEPTH environment variable > the built-in default of 3. So --depth always wins when supplied; otherwise APILEAK_MAX_DEPTH is honored if set; otherwise depth 3 is used.
Notes.
--depth 0performs only the depth-0 pass and disables recursion (equivalent to--no-recursive).--max-requestsdefaults to unbounded; when set, it caps the total number of discovery requests across all depths.--concurrencydefaults to50concurrent in-flight requests when not specified.--depthmust be>= 0;--max-requestsand--concurrencymust be>= 1.
| Option | Description | Default | Example |
|---|---|---|---|
--proxy |
Route all HTTP traffic through an intercepting proxy (Burp/Caido/Hetty). Also accepts a SOCKS5 URL, optionally with auth | - | --proxy http://127.0.0.1:8080 |
--proxy-verify-ssl |
Keep TLS verification on when proxying (after installing the proxy CA) | false |
--proxy-verify-ssl |
SOCKS5 dependency. Routing through a SOCKS5 proxy (e.g.
--proxy socks5://user:pass@host:port) requires the optionalhttpx[socks]extra to be installed (pip install "httpx[socks]"). Without it, SOCKS5 URLs are rejected by the underlying HTTP client. Plainhttp:///https://proxies need no extra dependency.
See Proxy Integration for details.
These flags harden and broaden discovery: they widen the candidate set (seeds and extensions), attach request context (headers/cookies/auth), refine which results are kept (response matchers/filters), enumerate methods and GraphQL surfaces, control per-request resilience and transport/TLS, scan responses for secrets, and emit machine-readable output. Unless noted otherwise these options apply to the dir command. The shared options -x/--extensions, --timeout, and --retries are also accepted by the scan command.
| Option | Description | Default | Example |
|---|---|---|---|
--wordlist, -w |
Wordlist file for discovery. Repeatable; values are merged and de-duplicated after normalization. Pass - to read entries from stdin (empty lines and # comment lines are skipped) |
wordlists/endpoints.txt |
-w a.txt -w b.txt / cat list.txt | ... -w - |
--openapi |
OpenAPI/Swagger document (JSON or YAML) to seed discovery from. Repeatable | - | --openapi api.yaml |
--postman |
Postman collection to seed discovery from. Repeatable | - | --postman collection.json |
--extensions, -x |
File extensions appended to each wordlist entry (comma-separated, repeatable). Leading dots are optional, so -x json,php and -x .json -x .php are equivalent. Also available on scan |
- | -x json,php |
Notes:
- Repeated
--wordlistvalues and--openapi/--postmanseeds are merged into a single candidate set with no duplicate normalized paths. If the merged candidate set is empty, the command completes without issuing any request and reports that no candidates were available. - An unparseable OpenAPI/Postman source is rejected with a descriptive error and no discovery is performed.
- Each extension expands a wordlist entry into the original entry plus one candidate per distinct normalized extension (so
Wentries withEdistinct extensions produceW × (E + 1)candidates per method). Every expanded candidate counts toward--max-requestsand stays within--concurrency.
Positional fuzzing places a literal keyword directly inside the target URL and sweeps each marked position with candidate values — the ffuf/wfuzz convention. This lets you fuzz a version segment, a filename, a query-parameter value, or several positions at once, instead of only appending wordlist entries to a base path.
| Option | Description | Default | Example |
|---|---|---|---|
--fuzz-keyword |
Literal token in the target URL that marks positions to fuzz. Every non-overlapping literal occurrence becomes a marker, scanned left-to-right. Matched as a plain literal (never a regex) | FUZZ |
--fuzz-keyword FUZZ |
--fuzz-mode |
How two or more markers combine their wordlists: clusterbomb (cartesian product) or pitchfork (index-wise pairing). Case-insensitive |
clusterbomb |
--fuzz-mode pitchfork |
How markers are detected. Every literal occurrence of the keyword in the target URL is treated as a marker (a Marker_Position), scanned left-to-right and counted as the number of non-overlapping occurrences. A marker may fall inside a path segment (as a substring or a whole segment), a query-parameter name or value, a filename, or a file extension. Substitution preserves every other character, path segment, and query parameter of the target URL unchanged.
When marker mode engages. Marker mode is active whenever the target URL contains the keyword. If the target URL contains no occurrence of the keyword — and no marker-only option was supplied — dir falls back to the existing base-path behavior, appending each wordlist entry to the base path via URL join.
Per-marker wordlist association. In marker mode the repeatable --wordlist values become the per-marker wordlists, associated with markers in the left-to-right order the markers occur (the first --wordlist is the wordlist of the first marker, and so on). This differs from the non-marker merge-and-de-duplicate behavior. Fallback rules:
- Fewer wordlists than markers: the last supplied wordlist fills every remaining marker that has no explicitly associated wordlist.
- Exactly one wordlist, two or more markers: that single wordlist is used for every marker.
- More wordlists than markers: rejected with a descriptive error (see below).
Combination modes. With two or more markers, --fuzz-mode controls how the per-marker wordlists combine:
clusterbomb(default): the cartesian product of all wordlists — every combination of one value per marker becomes a candidate. ForMmarkers with wordlist sizesW1 … WM, this generatesW1 × … × WMcandidates.pitchfork: the wordlists are iterated in parallel, pairing the i-th value of each list, stopping at the shortest wordlist —min(W1, …, WM)candidates. Use it to pair related lists position-by-position (e.g. a versions list with a matching filenames list).
A single marker reduces to exactly W candidates in either mode. Marker-generated candidates obey the same discovery controls as any other candidate: URL normalization and de-duplication, the --max-requests budget, the --concurrency limit, --rate-limit, the User-Agent options, the response matchers/filters, and --confirm-hits.
Choosing a distinct keyword. Because every literal occurrence of the keyword is treated as a marker, pick a keyword that does not appear in legitimate URL text. If FUZZ (or your chosen keyword) could collide with real path, query, or hostname text, choose a distinct token (for example __FUZZ__) to avoid creating unintended marker positions.
Marker-mode validation (exit-before-discovery). These configurations are rejected with a descriptive error and issue no requests:
- An empty or whitespace-only
--fuzz-keyword. - A marker-only option (
--fuzz-keywordor--fuzz-modegiven explicitly on the command line) while the target URL contains no occurrence of the keyword. - More
--wordlistsources than there are markers (the error names both counts). --fuzz-mode pitchforkwith an empty associated wordlist (the error identifies the empty wordlist).- A
--fuzz-modevalue other thanclusterbomborpitchfork. - An associated wordlist that cannot be read from its source (the error names the unreadable source).
| Option | Description | Default | Example |
|---|---|---|---|
--header, -H |
Custom header applied to every discovery request, in "Name: Value" format. Repeatable |
- | -H "X-API-Key: key123" |
--cookie |
Raw Cookie header string applied to every discovery request |
- | --cookie "session=abc123" |
--basic-auth |
HTTP Basic credentials as user:pass, sent as an Authorization header on every discovery request |
- | --basic-auth admin:secret |
Notes:
- These request-context settings are carried into the targeted follow-up scan launched from interactive triage.
--basic-authand--jwtare mutually exclusive; supplying both is rejected with a descriptive error and no discovery runs.- A
--basic-authvalue without a:separating user and password is rejected with a descriptive error and no discovery runs. - When
--load-sessionreloads a prior session, no requests are issued, so none of these options are applied to that run.
Matchers keep only results that satisfy them; filters exclude results that satisfy them. When both are present, matchers are applied first and filters are applied to the retained set. They compose conjunctively with --status-code. All of these options are repeatable.
| Option | Description | Example |
|---|---|---|
--match-size |
Keep results whose response body size (bytes) satisfies the expression | --match-size >100 |
--match-words |
Keep results whose response word count satisfies the expression | --match-words 10-20 |
--match-lines |
Keep results whose response line count satisfies the expression | --match-lines <50 |
--match-regex |
Keep results whose response body matches the regular expression | --match-regex "api_key" |
--match-time |
Keep results whose response time (seconds) satisfies the expression | --match-time >2 |
--filter-size |
Exclude results whose response body size (bytes) satisfies the expression | --filter-size 0 |
--filter-words |
Exclude results whose response word count satisfies the expression | --filter-words <5 |
--filter-lines |
Exclude results whose response line count satisfies the expression | --filter-lines 1 |
--filter-regex |
Exclude results whose response body matches the regular expression | --filter-regex "Not Found" |
--filter-time |
Exclude results whose response time (seconds) satisfies the expression | --filter-time >10 |
Expression forms. Numeric attributes (size, words, lines, time) accept >N, <N, an inclusive range N-M, or an exact value N. The regex attributes take a regular expression matched against the response body. A syntactically invalid expression (an unparseable regex or a non-numeric bound) is rejected with a descriptive error and no discovery is performed. A soft-404 baseline is derived automatically and matching noise is suppressed independently of these selectors.
| Option | Description | Default | Example |
|---|---|---|---|
--enumerate-methods |
After discovering an endpoint, issue an OPTIONS request and record the methods parsed from the Allow header. An absent/empty Allow records an empty set; a 405 marks the path valid under a different method |
false |
--enumerate-methods |
--graphql |
Probe common GraphQL paths and report whether introspection is enabled (read-only introspection query). No finding is recorded when no GraphQL endpoint is found | false |
--graphql |
Both are off by default, and each extra request they issue counts toward --max-requests and stays within --concurrency.
These options apply to both dir and scan.
| Option | Description | Default | Example |
|---|---|---|---|
--timeout |
Per-request timeout in seconds applied to every discovery request (must be > 0) |
10 |
--timeout 30 |
--retries |
Number of automatic retries for each failed discovery request (must be >= 0) |
2 |
--retries 5 |
A request exceeding --timeout is abandoned and retried up to --retries. A 429 response triggers automatic throttle/backoff that continues to honor the configured rate limit and concurrency. An invalid --timeout (not a positive number) or --retries (not a non-negative integer) is rejected with a descriptive error and no discovery is performed.
| Option | Description | Default | Example |
|---|---|---|---|
--client-cert |
Client certificate for mutual TLS, presented on every request. A combined cert+key PEM path, or a cert:key pair of paths |
- | --client-cert client.pem |
--ca-bundle |
Custom CA bundle used to verify target certificates for every request | - | --ca-bundle ca.pem |
--allow-cross-domain-redirects |
Follow redirects to other domains. By default discovery follows redirects only to the originating request's domain | false |
--allow-cross-domain-redirects |
--resolve |
Override DNS resolution for a host to a given IP for every request, expressed as host:ip |
- | --resolve api.example.com:127.0.0.1 |
Notes:
- A
--client-certor--ca-bundlepath that does not exist or cannot be read is rejected with a descriptive error naming the path, and no discovery is performed. - A
--resolvevalue not expressed ashost:ipis rejected with a descriptive error naming the value, and no discovery is performed. - SOCKS5 proxies are supplied through the existing
--proxyflag and require thehttpx[socks]extra (see the Proxy Options note above).
| Option | Description | Default | Example |
|---|---|---|---|
--detect-secrets |
Scan each discovery response body and headers for secrets/leaked credentials (read-only). Matched values are redacted in output | false |
--detect-secrets |
--secret-patterns |
Path to a JSON file mapping pattern names to regex strings used for secret detection. Defaults to the built-in patterns when omitted | built-in patterns | --secret-patterns patterns.json |
Secret detection is off by default. When enabled, a response with no matching content yields no finding; a match is tagged to the endpoint whose response contained it, with the matched value redacted.
| Option | Description | Default | Example |
|---|---|---|---|
--output-format |
Write a machine-readable discovery output in the selected format (csv or jsonl) |
- | --output-format jsonl |
--output-file |
Destination path for the machine-readable output (the extension selects the format) | - | --output-file results.jsonl |
Records are ordered consistently with the triage table, grouped by status class in ascending order. An unsupported format is rejected with a descriptive error and writes no file; a write failure on an unwritable path also errors. This is distinct from --export/--export-file, which produce a human-readable md/txt report.
These options decide which discovered records are ever persisted, applied at discovery time as a record is recorded. They are distinct from the display-only --status-code filter and the --match-*/--filter-* selectors, which act on records that have already been stored.
| Option | Description | Default | Example |
|---|---|---|---|
--include-path |
Only persist discovered endpoints whose path or URL matches the regular expression. Repeatable | - | --include-path "^/api/" |
--exclude-path |
Never persist discovered endpoints whose path or URL matches the regular expression. Repeatable; takes precedence over --include-path |
- | --exclude-path "\.png$" |
--include-status |
Only persist discovered endpoints whose status matches the selection — a status class (2xx) or explicit codes/ranges (200,404 or 200-300) |
- | --include-status 2xx |
--exclude-status |
Never persist discovered endpoints whose status matches the selection; takes precedence over --include-status |
- | --exclude-status 404 |
Exclude precedence (path). A candidate path or URL matching any --exclude-path pattern is neither tested nor stored, regardless of which --include-path patterns it also matches. When one or more --include-path patterns are supplied, a candidate must match at least one of them to be kept; with no include patterns, everything not excluded is kept.
Exclude precedence (status). A record whose status matches --exclude-status is dropped even if it also matches --include-status. With no --include-status, every status not excluded is kept.
Storage vs. display. These are storage-time decisions: a record dropped here never enters the discovery session file (--save-session), the machine-readable output (--output-format), or the triage table — regardless of any later display-only --status-code value. By contrast, --status-code, --match-*, and --filter-* only change which already-stored records are shown.
Validation. An --include-path/--exclude-path value that is not a valid regular expression, or an --include-status/--exclude-status value that is an explicit code outside 100-599 or a token that is neither a status class nor an explicit code, is rejected with a descriptive error naming the offending value, and no discovery is performed.
These options narrow which discovered endpoints recursion descends into. They are accepted by both dir and scan. They only ever narrow the default VALID/AUTH_REQUIRED recursion eligibility — they never relax it.
| Option | Description | Default | Example |
|---|---|---|---|
--recursion-status |
Restrict recursion to endpoints whose status class is in the comma-separated list of status classes (2xx,3xx) |
- | --recursion-status 2xx,3xx |
--recursion-type |
Restrict recursion to endpoints whose type is in the comma-separated list of endpoint types (admin, api_version, authentication, development, standard) |
- | --recursion-type admin,api_version |
Notes:
- When a recursion-scope option is supplied, only discovered records that satisfy every supplied selection are recursed into; the set recursed into is always a subset of the records that already satisfy the default recursion eligibility (VALID or AUTH_REQUIRED and not a catch-all response).
- Recursion still respects
--depth,--max-requests(every recursive request counts toward the budget),--concurrency, and catch-all suppression. - With no recursion-scope option, the existing recursion behavior is preserved unchanged.
- A
--recursion-statusstatus class or--recursion-typeendpoint type that is not recognized is rejected with a descriptive error naming the value, and no discovery is performed.
| Option | Description | Default | Example |
|---|---|---|---|
--confirm-hits |
Enable Hit_Confirmation: re-request each interesting candidate N times and record it only when the responses are consistent (must be >= 1) |
off | --confirm-hits 3 |
Hit confirmation is off by default. When enabled, each candidate interesting result is re-requested N times and is recorded only when the confirmation responses are consistent — meaning they share the same status class and a comparable response body size. Inconsistent (flaky or randomized) responses are not recorded, which reduces false positives. Each confirmation request counts toward --max-requests, stays within --concurrency, and honors the configured --rate-limit. A --confirm-hits value that is not an integer >= 1 is rejected with a descriptive error, and no discovery is performed.
| Option | Description | Default | Example |
|---|---|---|---|
--checkpoint |
Periodically write a discovery checkpoint to PATH so an interrupted run can be resumed (atomic writes) |
- | --checkpoint scan.ckpt |
--resume |
Resume an interrupted discovery run from the checkpoint at PATH (loaded before discovery) |
- | --resume scan.ckpt |
Checkpoint/resume contract:
- Checkpointing. With
--checkpoint, discovery periodically writes a checkpoint recording the candidates already tested and the results discovered so far. Writes are atomic (a temporary file is written then moved into place), so a failure never leaves a partially written checkpoint. A checkpoint path that cannot be written is rejected with a descriptive error. - Resuming. With
--resume, the checkpoint is loaded before any discovery runs. Candidates recorded as already tested are treated as tested and are not re-requested (no-recompute), and the checkpointed results are merged with newly discovered ones so the union contains no two records sharing the same(url, method)pair (no-duplication). - Combine them. Pass both
--resumeand--checkpointto resume a run and keep checkpointing it. - Validation. A
--resumecheckpoint that does not exist, cannot be read, or cannot be parsed into the expected checkpoint structure is rejected with a descriptive error naming the artifact, and no discovery is performed. - Separate from sessions. The discovery checkpoint is a distinct artifact from the
--save-session/--load-sessionsession file; it additionally records the in-flight tested candidates and is intended for resuming, not for triage reload.
The triage workflow is an additive layer on top of discovery. It is engaged automatically when you pass any of the flags below; otherwise dir behaves exactly as before. Discovered endpoints are projected into DiscoveryResult records (URL, method, status code, EndpointStatus) that can be grouped/filtered by status class, rendered as a rich table, saved to a structured session file, exported in a human-readable form, and used to drive an opt-in follow-up scan.
| Option | Description | Default | Example |
|---|---|---|---|
--save-session |
Save all discovery results to a JSON session file (the source of truth for reload) | - | --save-session session.json |
--load-session |
Reload discovery results exclusively from a JSON session file (skips discovery) | - | --load-session session.json |
--export |
Write a human-readable export in the selected format (md or txt) |
- | --export md |
--export-file |
Destination path for the human-readable export (the extension selects the format) | reports/discovery_export.<fmt> |
--export-file results.md |
--interactive, --triage |
Enable interactive triage mode (opt-in; auto-disabled in CI mode) | false |
--interactive |
--scan-scope |
Non-interactively select a batch of discovered records (2xx/3xx/4xx/5xx/valid/auth_required) and run an OWASP scan over them |
- | --scan-scope valid |
--ci-mode |
Enable CI mode; disables the interactive prompt so it never blocks a pipeline | false |
--ci-mode |
Key behaviors:
- Session file is the source of truth.
--load-sessionreads records only from the JSON session file; the human-readable export is never read back. - Atomic session writes. A failed
--save-sessionnever leaves a partially written file, and surfaces a descriptive error. - Triage table. Results render in a four-column table — URL, Method, Status, EndpointStatus — grouped by status class in ascending order (
2xx,3xx,4xx,5xx). An empty/filtered-to-empty result set shows the header row with zero data rows. - Export grouping. The
.md/.txtexport groups records by status class in the same ascending order. Any format other than.md/.txtis rejected with a descriptive error and writes nothing. - Interactive mode is opt-in and CI-safe. It is off by default, prompts for exactly one endpoint when enabled, re-prompts on invalid input up to 3 consecutive attempts (then abandons without a scan), and is automatically disabled under
--ci-modeso it never blocks.
Discovery can feed an OWASP scan directly over a set of discovered endpoints, so you don't have to launch a single-endpoint follow-up for each result. The batch scope can be selected interactively or non-interactively.
- Interactive multi-select. In interactive triage (
--interactive), entering two or more record indices — a comma list like1,3,5or a range like2-4— selects a batch scan scope and runs an OWASP scan over exactly those records. A single index keeps the existing single-endpoint follow-up. - Non-interactive
--scan-scope.--scan-scope <2xx|3xx|4xx|5xx|valid|auth_required>selects all discovered records of the chosen status class or EndpointStatus (validselects all VALID records,auth_requiredselects all AUTH_REQUIRED records) and runs an OWASP scan over them through thescancommand engine path. - CI-only non-interactive. Under
--ci-modethe batch scope is determined only from--scan-scope; the interactive selection prompt never runs and never blocks the pipeline. - Inherited request settings. The batch scan applies the same
--rate-limit, User-Agent option, and--header/--cookie/--basic-authrequest context supplied to the originatingdirinvocation. - Empty scope. If the determined scope is empty (no records match the token, or an empty multi-select), no scan runs and the command reports that there is nothing to scan.
- Invalid token. A
--scan-scopevalue that is neither a recognized status class nor a recognized EndpointStatus is rejected with a descriptive error naming the value, and no scan runs.
The --status-code flag accepts three forms in triage mode (parsed by parse_status_filter):
| Form | Example | Meaning |
|---|---|---|
| Status class token | 2xx, 3xx, 4xx, 5xx (case-insensitive) |
Keep records whose status code shares that leading digit |
| Explicit codes | 200,404,500 |
Keep records whose status code is exactly in the set |
| Ranges | 200-299, 400-403 |
Keep records whose status code falls in the range |
Notes:
- A class token is single-valued — use
2xxon its own, not2xx,404. - Explicit codes are validated to the inclusive range
100-599; an out-of-range value (e.g.700) is rejected with an error naming the offending value and exits non-zero. - Records whose leading digit is not 2-5 (for example a
1xx) are excluded from all status-class groups.
The dir command's usage examples are organized into three levels: basic uses, intermediate uses, and advanced uses. Each example includes a title, a short description of what it does and what it's for, and a ready-to-copy command. The more flags you combine, the closer the example gets to the advanced level.
Minimal examples to start discovering endpoints. They cover the target, the wordlist, HTTP methods, simple authentication, request pacing, and the output report name.
1. Basic discovery
Runs endpoint fuzzing against the target using the default wordlist (wordlists/endpoints.txt). It's the starting point for any reconnaissance.
python apileaks.py dir --target https://api.example.com2. Custom wordlist
Uses your own list of candidate paths instead of the default wordlist. Useful when you have a dictionary specific to the target's domain or technology.
python apileaks.py dir \
--target https://api.example.com \
--wordlist custom_endpoints.txt3. Restrict the HTTP methods tested
Restricts which HTTP verbs are tested on each candidate. Reduces the number of requests and the noise when you only care about certain methods.
python apileaks.py dir \
--target https://api.example.com \
--methods GET,POST4. Request pacing (rate limit)
Lowers the requests-per-second rate to be stealthier or avoid overwhelming the target. The default is 10 req/s.
python apileaks.py dir \
--target https://api.example.com \
--rate-limit 55. Authenticated discovery with a JWT
Attaches a JWT as a credential to discover endpoints that are only visible after authenticating.
python apileaks.py dir \
--target https://api.example.com \
--jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...6. Filter results by status code
Shows only the results whose status matches a class (2xx), explicit codes (200,401,403), or a range (400-403).
# Only successful responses (status class)
python apileaks.py dir \
--target https://api.example.com \
--status-code 2xx
# Explicit codes
python apileaks.py dir \
--target https://api.example.com \
--status-code 200,401,403
# A range of codes
python apileaks.py dir \
--target https://api.example.com \
--status-code 400-4037. Name the output file
Sets the base name of the generated report instead of letting it be auto-generated.
python apileaks.py dir \
--target https://api.example.com \
--output my-reconExamples that combine several discovery sources, request context, recursion control, and result persistence. These are the flags you'll use in a realistic reconnaissance.
1. Multiple wordlists and extensions
Merges several wordlists (de-duplicated after normalization) and expands each entry with file extensions. -w and -x are repeatable.
python apileaks.py dir \
--target https://api.example.com \
-w wordlists/endpoints.txt \
-w wordlists/admin.txt \
-x json,php2. Seed discovery from OpenAPI / Postman
Feeds discovery with paths extracted from an OpenAPI/Swagger spec or a Postman collection. Both flags are repeatable and combine with the wordlists.
python apileaks.py dir \
--target https://api.example.com \
--openapi api.yaml \
--postman collection.json3. Request context: headers, cookies, and Basic Auth
Attaches custom headers, a cookie, or HTTP Basic credentials to every discovery request. -H is repeatable.
python apileaks.py dir \
--target https://api.example.com \
-H "X-API-Key: key123" \
-H "X-Env: staging" \
--cookie "session=abc123" \
--basic-auth admin:secret4. Framework detection and version fuzzing
Detects the backend framework while fuzzing and enumerates API versions (/v1, /v2, /api/v1, ...). You can use them separately or together.
# Framework detection only
python apileaks.py dir \
--target https://api.example.com \
--detect-framework
# Framework detection + version fuzzing
python apileaks.py dir \
--target https://api.example.com \
--detect-framework \
--fuzz-versions5. User-Agent rotation (WAF evasion)
Changes the User-Agent to make detection harder. The three options are mutually exclusive: random, a fixed one, or rotation from a file.
# Random User-Agent from the built-in set
python apileaks.py dir \
--target https://api.example.com \
--user-agent-random
# A fixed User-Agent
python apileaks.py dir \
--target https://api.example.com \
--user-agent-custom "MyScanner/1.0"
# Round-robin rotation from a file
python apileaks.py dir \
--target https://api.example.com \
--user-agent-file user_agents.txt6. Recursion control (depth, budget, concurrency)
Tunes how deep discovery recurses, the total request budget, and how many run in parallel. Lets you balance coverage against speed.
python apileaks.py dir \
--target https://api.example.com \
--depth 5 \
--max-requests 5000 \
--concurrency 1007. Per-request resilience (timeout and retries)
Sets the per-request timeout and how many automatic retries to make on failure. Also accepted by scan.
python apileaks.py dir \
--target https://api.example.com \
--timeout 30 \
--retries 58. Session persistence and reload
Saves the full result set to a session file (the source of truth) and reloads it later without re-running discovery.
# Save the session
python apileaks.py dir \
--target https://api.example.com \
--save-session session.json
# Reload the session (skips discovery) and filter to server errors
python apileaks.py dir \
--target https://api.example.com \
--load-session session.json \
--status-code 5xx9. Human-readable export (Markdown / text)
Generates a readable report grouped by status class, in md or txt. You can save the session and export in the same run.
python apileaks.py dir \
--target https://api.example.com \
--save-session session.json \
--export md \
--export-file results.md10. Machine-readable output (CSV / JSONL)
Writes a machine-processable output in csv or jsonl, distinct from the human-readable export. The file extension selects the format.
python apileaks.py dir \
--target https://api.example.com \
--output-format jsonl \
--output-file results.jsonl11. Route through an intercepting proxy (Burp / Caido / Hetty)
Sends all traffic through a proxy to inspect and replay requests. Also accepts SOCKS5 URLs (requires httpx[socks]).
python apileaks.py dir \
--target https://api.example.com \
--proxy http://127.0.0.1:8080Examples that exploit the discovery engine's fine-grained capabilities: positional fuzzing, matchers/filters, method and GraphQL probing, secret detection, storage and recursion scope, hit confirmation, checkpoint/resume, TLS, interactive triage, and integration with the OWASP scan.
1. Positional fuzzing with markers (clusterbomb / pitchfork)
Places a literal keyword inside the target URL and sweeps each marked position with candidate values (ffuf/wfuzz convention). With multiple markers, --fuzz-mode controls how the wordlists combine.
# One marker in the version segment
python apileaks.py dir \
--target "https://api.example.com/FUZZ/users" \
--fuzz-keyword FUZZ \
-w versions.txt
# Two markers, cartesian product (clusterbomb)
python apileaks.py dir \
--target "https://api.example.com/FUZZ/FUZZ" \
--fuzz-keyword FUZZ \
--fuzz-mode clusterbomb \
-w versions.txt \
-w endpoints.txt
# Two markers paired position-by-position (pitchfork)
python apileaks.py dir \
--target "https://api.example.com/__FUZZ__/__FUZZ__" \
--fuzz-keyword __FUZZ__ \
--fuzz-mode pitchfork \
-w versions.txt \
-w filenames.txt2. Response matchers and filters
Keeps (--match-*) or excludes (--filter-*) results by size, words, lines, time, or a body regex. All are repeatable and compose with --status-code.
python apileaks.py dir \
--target https://api.example.com \
--match-size ">100" \
--match-regex "api_key" \
--filter-regex "Not Found" \
--filter-size 03. Method enumeration and GraphQL probing
After discovering an endpoint, issues OPTIONS to record the methods from the Allow header, and probes common GraphQL paths reporting whether introspection is enabled.
python apileaks.py dir \
--target https://api.example.com \
--enumerate-methods \
--graphql4. Secret and leaked-credential detection
Scans each response body and headers for secrets (read-only). Matched values are redacted in the output. You can supply your own patterns.
python apileaks.py dir \
--target https://api.example.com \
--detect-secrets \
--secret-patterns patterns.json5. Path and status scope (storage-time selection)
Decides which records ever get persisted. Exclude patterns take precedence over include patterns. Unlike --status-code, this acts before storing.
python apileaks.py dir \
--target https://api.example.com \
--include-path "^/api/" \
--exclude-path "\.png$" \
--include-status 2xx \
--exclude-status 4046. Recursion scope
Restricts which endpoints recursion descends into, by status class and/or endpoint type. It only narrows the default eligibility, never relaxes it.
python apileaks.py dir \
--target https://api.example.com \
--recursion-status 2xx,3xx \
--recursion-type admin,api_version7. Hit confirmation (reduce false positives)
Re-requests each interesting candidate N times and only records it if the responses are consistent (same status class and comparable size).
python apileaks.py dir \
--target https://api.example.com \
--confirm-hits 38. Checkpoint and resume
Writes periodic checkpoints (atomic writes) so an interrupted discovery can be resumed. Combine --resume and --checkpoint to resume and keep saving.
# Run while saving checkpoints
python apileaks.py dir \
--target https://api.example.com \
--checkpoint scan.ckpt
# Resume from the checkpoint and keep saving
python apileaks.py dir \
--target https://api.example.com \
--resume scan.ckpt \
--checkpoint scan.ckpt9. Transport and TLS (mTLS, custom CA, DNS, redirects)
Presents a client certificate for mTLS, verifies with a custom CA, overrides DNS resolution, and allows cross-domain redirects.
python apileaks.py dir \
--target https://api.example.com \
--client-cert client.pem \
--ca-bundle ca.pem \
--resolve api.example.com:127.0.0.1 \
--allow-cross-domain-redirects10. Interactive triage and targeted follow-up
Enables the interactive triage table (opt-in). Selecting an endpoint launches a follow-up scan that inherits the rate limit, User-Agent, and request context. --triage is an alias for --interactive.
python apileaks.py dir \
--target https://api.example.com \
--load-session session.json \
--status-code 2xx \
--interactive11. Discovery-to-scan integration (batch scan)
Feeds an OWASP scan directly over a batch of discovered endpoints, non-interactively, selecting by status class or EndpointStatus.
python apileaks.py dir \
--target https://api.example.com \
--scan-scope valid12. CI/CD-safe run
CI mode disables the interactive prompt so it never blocks the pipeline, even if --interactive is passed. Combine it with --scan-scope for non-interactive batch scanning.
python apileaks.py dir \
--target https://api.example.com \
--interactive \
--ci-mode \
--scan-scope valid \
--save-session session.json \
--export md \
--export-file results.md13. Combining rate limit + User-Agent with recursion and triage
--rate-limit and the User-Agent options apply to every request and are inherited by the targeted follow-up. Here they're combined with bounded recursion and interactive triage.
python apileaks.py dir \
--target https://api.example.com \
--rate-limit 10 \
--user-agent-file user_agents.txt \
--depth 5 \
--max-requests 8000 \
--save-session session.json \
--interactive14. Full triage workflow (all in one invocation)
Discover, detect framework, filter to successful endpoints, save the session, export Markdown, and open the interactive prompt — all in a single command.
python apileaks.py dir \
--target https://api.example.com \
--wordlist wordlists/endpoints.txt \
--rate-limit 10 \
--detect-framework \
--status-code 2xx \
--save-session session.json \
--export md \
--export-file discovery.md \
--interactive--rate-limit and the three User-Agent options apply to every discovery request the dir command issues, and they compose freely with the discovery-control and triage flags (--depth, --max-requests, --save-session, --status-code, --interactive). The same settings are also inherited by the targeted follow-up scan launched from interactive triage (see notes below).
Rate limit + each User-Agent option, combined with discovery/triage flags
# Random User-Agent rotation + gentle rate limit, bounded recursive discovery,
# saving a session for later triage
python apileaks.py dir \
--target https://api.example.com \
--rate-limit 5 \
--user-agent-random \
--depth 4 \
--max-requests 5000 \
--status-code 2xx \
--save-session session.json
# Custom (single) User-Agent + rate limit, with interactive triage so the
# follow-up scan inherits both settings
python apileaks.py dir \
--target https://api.example.com \
--rate-limit 8 \
--user-agent-custom "MyScanner/1.0" \
--status-code 2xx \
--save-session session.json \
--interactive
# Rotating User-Agents from a file + rate limit, deep discovery with a budget,
# saving a session and opening interactive triage
python apileaks.py dir \
--target https://api.example.com \
--rate-limit 10 \
--user-agent-file user_agents.txt \
--depth 5 \
--max-requests 8000 \
--save-session session.json \
--interactiveNotes.
- Mutually exclusive User-Agent options. Exactly one of
--user-agent-random,--user-agent-custom "<UA>", or--user-agent-file <list.txt>may be supplied per invocation. Passing more than one is rejected with an error that names the conflict, and no discovery is performed. --user-agent-customuses the single supplied string as the User-Agent for every discovery request.--user-agent-randompicks a User-Agent at random from the built-in set for each discovery request.--user-agent-fileloads User-Agents from the file, one per line; empty lines and lines whose first non-whitespace character is#(comments) are skipped. The loaded strings are then rotated in round-robin order across discovery requests. A missing or unreadable file path is rejected with an error naming the path, and no discovery is performed.--rate-limitapplies only to requests actually issued. When--load-sessionreloads a prior session, no discovery requests are made, so the rate limit is not applied to that run.- Targeted follow-up inherits these settings. The
Targeted_Follow_Up_Scanlaunched from interactive triage reuses the same--rate-limitand User-Agent option (random / custom / file) from the originatingdirinvocation, applying them to every request it issues. A--user-agent-filelist is reloaded and rotated for the follow-up the same way.
Discover hidden, undocumented, or debug parameters accepted by an API endpoint. The par command injects candidate parameter names from a wordlist and compares responses against a baseline to detect parameters that alter application behavior. See the Parameter Fuzzing Guide for a comprehensive walkthrough.
python apileaks.py par [OPTIONS]| Option | Description | Example |
|---|---|---|
--target, -t |
Target URL to scan | --target https://api.example.com/users |
| Option | Description | Default | Example |
|---|---|---|---|
--wordlist, -w |
Wordlist file (repeatable, merged/deduped). Use - for stdin |
wordlists/parameters.txt |
--wordlist params.txt |
--methods |
HTTP methods to test (comma-separated: GET,POST,PUT,PATCH,DELETE). Controls injection points: GET/DELETE → query, POST/PUT/PATCH → body | GET,POST |
--methods POST,PUT |
--confirm-hits |
Re-test each candidate N times to confirm (≥1). Only stable hits are reported | Off | --confirm-hits 3 |
--max-requests |
Request budget: stop after N total requests (≥1) | Unbounded | --max-requests 1000 |
| Option | Description | Default | Example |
|---|---|---|---|
-H, --header |
Custom header (repeatable, Name: Value format) |
— | -H "X-API-Key: abc" |
--cookie |
Cookie value (sent as Cookie header) |
— | --cookie "session=xyz" |
--basic-auth |
Basic authentication (user:pass) |
— | --basic-auth admin:secret |
--jwt |
JWT bearer token | — | --jwt eyJ0eXAi... |
| Option | Description | Default | Example |
|---|---|---|---|
--timeout |
Per-request timeout in seconds (>0) | Same as dir |
--timeout 20 |
--retries |
Retry count for failed requests (≥0) | Same as dir |
--retries 3 |
--concurrency |
Max in-flight requests (≥1) | Same as dir |
--concurrency 50 |
--rate-limit |
Requests per second limit | 10 |
--rate-limit 5 |
| Option | Description | Default | Example |
|---|---|---|---|
--client-cert |
Client TLS certificate path | — | --client-cert client.pem |
--ca-bundle |
Custom CA bundle path | — | --ca-bundle ca.pem |
--resolve |
DNS resolution override (host:ip) |
— | --resolve api.example.com:10.0.1.50 |
Response matchers retain findings; filters exclude them. Matchers are applied before filters, consistent with dir.
| Option | Description | Example |
|---|---|---|
--match-size |
Keep findings by response size | --match-size ">100" |
--match-words |
Keep findings by word count | --match-words ">10" |
--match-lines |
Keep findings by line count | --match-lines ">5" |
--match-regex |
Keep findings matching regex | --match-regex "admin" |
--match-time |
Keep findings by response time | --match-time ">2.0" |
--filter-size |
Exclude findings by response size | --filter-size "<50" |
--filter-words |
Exclude findings by word count | --filter-words "<3" |
--filter-lines |
Exclude findings by line count | --filter-lines "<2" |
--filter-regex |
Exclude findings matching regex | --filter-regex "Not Found" |
--filter-time |
Exclude findings by response time | --filter-time "<0.1" |
| Option | Description | Default | Example |
|---|---|---|---|
--output-format |
Output format (csv or jsonl) |
— | --output-format jsonl |
--output-file |
Output file path | — | --output-file findings.jsonl |
| Option | Description | Default | Example |
|---|---|---|---|
--output, -o |
Report filename prefix | Auto-generated | --output param-scan |
--log-level |
Logging level | WARNING |
--log-level INFO |
--log-file |
Log file path | Console only | --log-file param.log |
--json-logs |
Output logs in JSON format | false |
--json-logs |
--response |
Filter by response codes (legacy) | All codes | --response 200,400 |
--status-code |
Show only specific status codes | All codes | --status-code 200,500-599 |
--proxy |
HTTP/SOCKS proxy URL | — | --proxy http://127.0.0.1:8080 |
par reports all discovered parameters as PARAMETER_FOUND. Severity is set based on the parameter name:
| Condition | Severity | OWASP | When |
|---|---|---|---|
| Generic parameter name | INFO | — | Default for any discovered parameter |
Name contains URL keyword (url, uri, host, endpoint, target, webhook, callback, redirect, src, source, feed, imageUrl, etc.) |
MEDIUM | API7 | Parameter likely carries a URL → potential SSRF surface |
When a MEDIUM finding is reported, the recommendation includes a ready-to-use SSRF test payload so the operator can immediately follow up with owasp ssrf.
| --proxy-verify-ssl | Keep TLS verification with proxy | Off | --proxy-verify-ssl |
| --no-banner | Suppress startup banner | Off | --no-banner |
Same as directory fuzzing — see above.
| Option | Description | Default | Example |
|---|---|---|---|
--detect-framework, --df |
Enable framework detection | false |
--detect-framework |
# Discover hidden parameters using the default wordlist
python apileaks.py par --target https://api.example.com/users/123
# With authentication and custom wordlist
python apileaks.py par \
--target https://api.example.com/api/v1/users \
--jwt "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
--wordlist custom_parameters.txt
# Fuzz only POST body parameters
python apileaks.py par \
--target https://api.example.com/api/v1/orders \
--methods POST
# Limit total requests
python apileaks.py par \
--target https://api.example.com/search \
--max-requests 500# Hit confirmation to reduce false positives
python apileaks.py par \
--target https://api.example.com/api/v1/search \
--confirm-hits 3 \
--max-requests 1500
# Multiple wordlists merged and deduped
python apileaks.py par \
--target https://api.example.com/api/v1/users \
--wordlist wordlists/parameters.txt \
--wordlist wordlists/admin_params.txt
# Request context: headers, cookie, and basic auth
python apileaks.py par \
--target https://internal-api.example.com/config \
-H "X-Tenant: acme" \
--cookie "session=abc123" \
--basic-auth admin:s3cr3t
# Resilience against a slow target
python apileaks.py par \
--target https://slow-api.example.com/endpoint \
--timeout 30 \
--retries 3 \
--rate-limit 3# Full-featured scan: auth, confirmation, budget, matchers, machine output
python apileaks.py par \
--target https://api.example.com/api/v1/users/me \
--jwt "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "X-Correlation-ID: pentest-001" \
--wordlist wordlists/parameters.txt \
--wordlist wordlists/debug_params.txt \
--methods GET,POST \
--confirm-hits 3 \
--max-requests 2000 \
--rate-limit 10 \
--timeout 20 \
--concurrency 25 \
--match-size ">100" \
--filter-regex "Not Found" \
--output-format jsonl \
--output-file reports/par_findings.jsonl
# Mutual TLS + DNS override for internal APIs
python apileaks.py par \
--target https://internal-api.example.com/admin \
--client-cert certs/client.pem \
--ca-bundle certs/internal-ca.pem \
--resolve internal-api.example.com:10.0.1.50 \
--basic-auth auditor:pass
# CI pipeline: bounded, quiet, machine-readable
python apileaks.py par \
--target "${API_ENDPOINT}" \
--jwt "${JWT_TOKEN}" \
--max-requests 1000 \
--confirm-hits 2 \
--output-format jsonl \
--output-file reports/par_ci.jsonl \
--no-banner
# WAF evasion with random user agents
python apileaks.py par \
--target https://protected-api.example.com/endpoint \
--user-agent-random \
--rate-limit 3 \
--timeout 20
# Through an intercepting proxy (Burp/Caido)
python apileaks.py par \
--target https://api.example.com/api/v1/orders \
--proxy http://127.0.0.1:8080 \
--jwt "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."The scan command is APILeak's primary orchestrator. It runs endpoint discovery and then executes all registered OWASP API Security Top 10 modules by default, aggregating every finding through the unified reporting pipeline and driving the CI/CD severity gate. Use --modules a,b to restrict the run to selected module keys.
To run a single OWASP module in isolation (red-team focus), use the owasp <key> command instead.
Deprecation.
fullandmainare deprecated, hidden aliases ofscan. They forward toscanunchanged (emitting a one-line stderr deprecation notice) and are retained only for backward compatibility — migrate scripts toscan. A single-module alias invocation such asfull --modules bolashould becomeapileaks owasp bola.
python apileaks.py scan [OPTIONS]| Option | Description | Example |
|---|---|---|
--target, -t |
Target URL to scan (required if no config) | --target https://api.example.com |
| Option | Description | Example |
|---|---|---|
--config, -c |
Configuration file path (YAML/JSON) | --config config/api.yaml |
| Option | Description | Default | Example |
|---|---|---|---|
--output, -o |
Output filename for reports | Auto-generated | --output comprehensive-scan |
--log-level |
Logging level | WARNING |
--log-level INFO |
--log-file |
Log file path | Console only | --log-file full-scan.log |
--json-logs |
Output logs in JSON format | false |
--json-logs |
--rate-limit |
Requests per second limit | 10 |
--rate-limit 15 |
--jwt |
JWT token for authentication | - | --jwt eyJ0eXAi... |
--status-code |
Show only specific status codes | All codes | --status-code 200,401,403 |
| Option | Description | Default | Example |
|---|---|---|---|
--modules |
Comma-separated OWASP modules | All modules | --modules bola,auth,property |
Available modules:
bola- BOLA (Broken Object Level Authorization) testing — API1auth- Authentication testing (JWT vulnerabilities) — API2property- Property Level Authorization testing — API3resource- Unrestricted Resource Consumption testing — API4function_auth- Function Level Authorization testing — API5business_flow- Unrestricted Access to Sensitive Business Flows — API6ssrf- Server-Side Request Forgery testing — API7security_misconfig- Security Misconfiguration (CORS, missing headers) — API8inventory- Improper Inventory Management (deprecated/undocumented versions) — API9unsafe_consumption- Unsafe Consumption of APIs — API10
Same as directory fuzzing - see above.
| Option | Description | Default | Example |
|---|---|---|---|
--detect-framework, --df |
Enable framework detection | false |
--detect-framework |
--fuzz-versions, --fv |
Enable API version fuzzing | false |
--fuzz-versions |
--framework-confidence |
Framework detection confidence | 0.6 |
--framework-confidence 0.8 |
--version-patterns |
Custom version patterns | Default patterns | --version-patterns /v1,/v2,/api/v1 |
--enable-advanced |
Enable all advanced features | false |
--enable-advanced |
--enable-payload-encoding |
Enable payload encoding/obfuscation | false |
--enable-payload-encoding |
--enable-waf-evasion |
Enable WAF detection and evasion | false |
--enable-waf-evasion |
--enable-subdomain-discovery |
Enable subdomain discovery | false |
--enable-subdomain-discovery |
--enable-cors-analysis |
Enable CORS analysis | false |
--enable-cors-analysis |
These flags tune recursive discovery so you can trade breadth for speed. They keep recursion agile: stay shallow and fast for a quick sweep, or go deep and thorough when you need full coverage — always bounded by the request budget and catch-all detection.
| Option | Description | Default | Example |
|---|---|---|---|
--depth |
Max recursion depth for discovery (0 = no recursion, depth-0 pass only) |
3 (see precedence below) |
--depth 5 |
--recursive / --no-recursive |
Enable or disable recursive discovery | enabled | --no-recursive |
--max-requests |
Global request budget for discovery | unbounded | --max-requests 5000 |
--concurrency |
Max concurrent in-flight discovery requests | 50 |
--concurrency 100 |
Depth precedence. The effective recursion depth is resolved as: explicit CLI --depth > the APILEAK_MAX_DEPTH environment variable > the built-in default of 3. So --depth always wins when supplied; otherwise APILEAK_MAX_DEPTH is honored if set; otherwise depth 3 is used.
Notes.
--depth 0performs only the depth-0 pass and disables recursion (equivalent to--no-recursive).--max-requestsdefaults to unbounded; when set, it caps the total number of discovery requests across all depths.--concurrencydefaults to50concurrent in-flight requests when not specified.--depthmust be>= 0;--max-requestsand--concurrencymust be>= 1.
The scan command accepts the same recursion-scope options as dir to narrow which discovered endpoints recursion descends into. They only narrow the default VALID/AUTH_REQUIRED recursion; they never relax it.
| Option | Description | Default | Example |
|---|---|---|---|
--recursion-status |
Restrict recursion to endpoints whose status class is in the comma-separated list of status classes (2xx,3xx) |
- | --recursion-status 2xx,3xx |
--recursion-type |
Restrict recursion to endpoints whose type is in the comma-separated list of endpoint types (admin, api_version, authentication, development, standard) |
- | --recursion-type admin,api_version |
An unrecognized --recursion-status status class or --recursion-type endpoint type is rejected with a descriptive error naming the value, and no discovery is performed. See the dir command's Recursion Scope notes for the full behavior.
The scan command shares the discovery seed and per-request resilience controls described in detail under the dir command's Discovery Robustness Options. The following are accepted by scan:
| Option | Description | Default | Example |
|---|---|---|---|
--extensions, -x |
File extensions appended to each wordlist entry (comma-separated, repeatable; leading dots optional) | - | -x json,php |
--timeout |
Per-request timeout in seconds applied to every discovery request (must be > 0) |
10 |
--timeout 30 |
--retries |
Number of automatic retries for each failed discovery request (must be >= 0) |
2 |
--retries 5 |
Invalid --timeout or --retries values are rejected with a descriptive error before any discovery runs. The richer request-context, response-matcher/filter, GraphQL, transport/TLS, secret-detection, and machine-readable-output options are specific to the dir command.
| Option | Description | Default | Example |
|---|---|---|---|
--ci-mode |
Enable CI/CD mode with deterministic exit codes and artifact generation | false |
--ci-mode |
--fail-on |
Fail on findings of this severity or higher | high |
--fail-on high |
--sarif |
Generate a SARIF 2.1.0 report (for code scanning / CI integration) | false |
--sarif |
--safe-mode |
Non-destructive scan: skip state-changing probes (POST/PUT/PATCH/DELETE) and restrict to safe methods | false |
--safe-mode |
--baseline |
Path to a baseline JSON report; only new findings drive the severity gate (missing path treats all findings as new) | - | --baseline baseline.json |
Available severity levels: critical, high, medium, low
Default gate. The severity gate default is now
high(it was previouslycritical). Runs without an explicit--fail-onfail on high or critical findings. Pass--fail-on criticalto keep the old behavior.
The scan command's usage examples are organized into three levels: basic uses, intermediate uses, and advanced uses. Each example includes a title, a short description of what it does and what it's for, and a ready-to-copy command. Remember that a plain scan already runs discovery plus all ten OWASP API Security Top 10 modules; the more flags you combine, the closer the example gets to the advanced level.
Minimal examples to run an orchestrated assessment. They cover the target, authentication, module selection, the output report name, status filtering, request pacing, and using a config file.
1. Basic scan
Runs endpoint discovery followed by all ten OWASP modules by default, aggregating every finding into one report. It's the starting point for a full-coverage assessment.
python apileaks.py scan --target https://api.example.com2. Authenticated scan with a JWT
Attaches a JWT so discovery and every OWASP module test the target as an authenticated user.
python apileaks.py scan \
--target https://api.example.com \
--jwt "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."3. Restrict to specific OWASP modules
Limits the run to a subset of modules instead of all ten, aggregating their findings into a single report.
python apileaks.py scan \
--target https://api.example.com \
--modules bola,auth,property4. Name the output report
Sets the base name of the generated report instead of letting it be auto-generated.
python apileaks.py scan \
--target https://api.example.com \
--output comprehensive-scan5. Filter shown status codes
Shows only responses matching the given codes/ranges, reducing noise during the run.
python apileaks.py scan \
--target https://api.example.com \
--status-code 200,401,4036. Adjust request pacing (rate limit)
Raises or lowers the requests-per-second rate for the whole scan. The default is 10 req/s.
python apileaks.py scan \
--target https://api.example.com \
--rate-limit 157. Use a configuration file
Drives the scan from a YAML/JSON config, keeping repeatable settings out of the command line.
python apileaks.py scan \
--config config/production_api.yaml \
--target https://api.example.comExamples that tune discovery, evasion, resilience, and logging on top of the orchestrated run. These are the flags you'll reach for in a realistic assessment.
1. Framework detection and version fuzzing
Detects the backend framework and enumerates API versions during discovery, tuning the detection confidence and the version patterns searched.
python apileaks.py scan \
--target https://api.example.com \
--detect-framework \
--fuzz-versions \
--framework-confidence 0.8 \
--version-patterns /v1,/v2,/api/v12. User-Agent rotation (WAF evasion)
Rotates the User-Agent to make detection harder. The three options (random, fixed, file) are mutually exclusive.
python apileaks.py scan \
--target https://api.example.com \
--user-agent-random3. Seed extensions and per-request resilience
Expands wordlist entries with file extensions and hardens each discovery request with a timeout and retries.
python apileaks.py scan \
--target https://api.example.com \
-x json,php \
--timeout 30 \
--retries 54. Recursion control (depth, budget, concurrency)
Tunes how deep discovery recurses, the total request budget, and how many requests run in parallel.
python apileaks.py scan \
--target https://api.example.com \
--depth 5 \
--max-requests 5000 \
--concurrency 1005. Recursion scope
Restricts which discovered endpoints recursion descends into, by status class and/or endpoint type. It only narrows the default eligibility, never relaxes it.
python apileaks.py scan \
--target https://api.example.com \
--recursion-status 2xx,3xx \
--recursion-type admin,api_version6. Route through an intercepting proxy
Sends all scan traffic through Burp/Caido/Hetty. TLS verification is auto-disabled while proxying; re-enable it with --proxy-verify-ssl after installing the proxy CA.
python apileaks.py scan \
--target https://api.example.com \
--modules bola,auth,ssrf \
--proxy http://127.0.0.1:80807. Structured logging to a file
Emits JSON-formatted logs to a file at a chosen verbosity, useful for pipelines and later analysis.
python apileaks.py scan \
--target https://api.example.com \
--log-level INFO \
--log-file full-scan.log \
--json-logsExamples that exploit the scan's full capabilities: bundled advanced discovery features, non-destructive runs, SARIF and baseline-gated CI/CD integration, and automated JWT detection with real key material.
1. Enable all advanced discovery features
Turns on the full advanced discovery bundle in one flag and pairs it with User-Agent rotation.
python apileaks.py scan \
--target https://api.example.com \
--enable-advanced \
--user-agent-random \
--output advanced-security-scan2. Toggle individual advanced features
Enables specific advanced capabilities — payload encoding/obfuscation, WAF detection/evasion, subdomain discovery, and CORS analysis — without the full bundle.
python apileaks.py scan \
--target https://api.example.com \
--enable-payload-encoding \
--enable-waf-evasion \
--enable-subdomain-discovery \
--enable-cors-analysis3. Non-destructive scan
Restricts the run to safe methods and skips state-changing probes (POST/PUT/PATCH/DELETE), suitable for shared or production-like environments.
python apileaks.py scan \
--target https://api.example.com \
--safe-mode \
--modules bola,auth,security_misconfig4. Generate a SARIF report
Emits a SARIF 2.1.0 report for code-scanning dashboards alongside the standard report.
python apileaks.py scan \
--target https://api.example.com \
--sarif \
--output scan-results5. CI/CD gate with SARIF
Enables CI mode with deterministic exit codes, fails the pipeline on high or critical findings, and emits a SARIF artifact.
python apileaks.py scan \
--target https://api.example.com \
--ci-mode \
--fail-on high \
--sarif6. Baseline-gated CI/CD
Compares against a baseline report so only newly introduced findings drive the severity gate.
python apileaks.py scan \
--target https://api.example.com \
--ci-mode \
--fail-on medium \
--baseline reports/previous-scan.json7. Full CI/CD: non-destructive, baseline-gated, with SARIF
Combines CI mode, safe methods, baseline gating, and a SARIF artifact into one pipeline-ready invocation.
python apileaks.py scan \
--target https://api.example.com \
--ci-mode \
--fail-on high \
--safe-mode \
--sarif \
--baseline reports/baseline.json8. Automated JWT detection with key material
Feeds the auth module real key material so the algorithm-confusion and expired-token-acceptance checks run with a public key (or a JWKS URL) and a known signing secret.
python apileaks.py scan \
--target https://api.example.com \
--modules auth \
--public-key ./idp_public.pem \
--signing-secret 's3cr3t'9. Deep discovery combined with a full orchestrated scan
Combines bounded deep recursion, extensions, resilience, and framework detection with the full module set for maximum coverage.
python apileaks.py scan \
--target https://api.example.com \
--detect-framework \
--fuzz-versions \
--depth 5 \
--max-requests 8000 \
--concurrency 100 \
-x json,php \
--timeout 30 \
--retries 5 \
--output deep-scanThe owasp command group exposes each OWASP API Security Top 10 detection module as a first-class subcommand so you can run exactly one module in isolation (a red-team focus), rather than the full orchestrated scan.
apileaks owasp(no subcommand) prints one line per registered module — its key, OWASP category, and a one-line summary.apileaks owasp <key> --target URLruns only that module against the target.
Each module subcommand accepts the shared transversal options; bola and auth additionally accept their own module-specific options (the other eight modules accept transversal options only).
| Key | OWASP | Summary |
|---|---|---|
bola |
API1 | Broken Object Level Authorization (BOLA) detection |
auth |
API2 | Broken Authentication detection |
property |
API3 | Broken Object Property Level Authorization detection |
resource |
API4 | Unrestricted Resource Consumption detection |
function_auth |
API5 | Broken Function Level Authorization detection |
business_flow |
API6 | Unrestricted Access to Sensitive Business Flows detection |
ssrf |
API7 | Server-Side Request Forgery (SSRF) detection |
security_misconfig |
API8 | Security Misconfiguration detection |
inventory |
API9 | Improper Inventory Management detection |
unsafe_consumption |
API10 | Unsafe Consumption of APIs detection |
# List every module (key, OWASP category, summary)
python apileaks.py owasp
# Run exactly one module in isolation
python apileaks.py owasp <key> --target URL [OPTIONS]# List all available modules
python apileaks.py owasp
# Run only the BOLA module against a target
python apileaks.py owasp bola --target https://api.example.com
# Run only Broken Authentication detection with a JWT
python apileaks.py owasp auth \
--target https://api.example.com \
--jwt "eyJ0eXAiOiJKV1Q..."
# Run only the SSRF module
python apileaks.py owasp ssrf --target https://api.example.comWhen to use which. Prefer
scanfor full-coverage assessments and CI gating (it runs discovery + all modules and drives--ci-mode/--fail-on/--sarif/--baseline/--safe-mode). Reach forowasp <key>when you want to focus on a single vulnerability class. Usescan --modules a,bwhen you want a subset of two or more modules aggregated in one report. A deprecatedfull --modules bolainvocation maps directly toapileaks owasp bola.
APILeak includes comprehensive JWT security testing utilities organized as a command group.
All JWT utilities are accessed through the jwt command group:
python apileaks.py jwt [SUBCOMMAND] [OPTIONS]This is a brief reference. For the full JWT attack methodology and deep-dive walkthroughs, see JWT Attacks.
| Subcommand | Purpose | Description |
|---|---|---|
decode |
Token Analysis | Decode and analyze JWT tokens |
encode |
Token Generation | Create JWT tokens for testing |
verify |
Signature Verification | Verify a token's signature (HMAC secret or public key) |
genkey |
Key Generation | Generate an RSA or EC keypair for testing |
jwks-to-key |
JWKS Conversion | Convert a JWKS entry to a PEM public key |
test-alg-none |
Algorithm Confusion | Test alg:none vulnerability (signature stripping) |
test-null-signature |
Null Signature | Test null signature bypass (signature stripping) |
test-alg-confusion |
Key Confusion | Test RS256/ES256→HS256 substitution attack |
brute-secret |
Secret Brute-force | Crack weak HMAC secrets (bruteforcing HS256 key) |
test-kid-injection |
Key ID Injection | Test kid parameter injection |
test-jwks-spoof |
JWKS Spoofing | Test JWKS URL spoofing |
test-inline-jwks |
Inline JWKS | Test inline JWKS injection |
attack-test |
Comprehensive Suite | Run all attack vectors against a live endpoint |
Every test-* subcommand (and attack-test) accepts the following options to validate an attack against a real endpoint:
| Option | Description | Example |
|---|---|---|
-u, --url |
Target URL to test the attack against | --url https://api.example.com/protected |
-H, --header |
Custom header (repeatable) | -H "X-API-Key: key123" |
-d, --data |
POST data for endpoint testing | -d '{"action":"read"}' |
--timeout |
Request timeout in seconds | --timeout 30 |
Decode and analyze JWT tokens with security insights.
python apileaks.py jwt decode TOKEN| Argument | Description | Example |
|---|---|---|
TOKEN |
JWT token to decode | eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... |
python apileaks.py jwt decode eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cCreate JWT tokens for testing purposes.
python apileaks.py jwt encode PAYLOAD [OPTIONS]| Argument | Description | Example |
|---|---|---|
PAYLOAD |
JWT payload as JSON string | '{"sub":"user123","role":"admin"}' |
| Option | Description | Default | Example |
|---|---|---|---|
--header |
JWT header as JSON string | {"alg":"HS256","typ":"JWT"} |
--header '{"alg":"HS512","typ":"JWT"}' |
--secret |
Secret key for signing | secret |
--secret mysecretkey |
# Basic JWT encoding
python apileaks.py jwt encode '{"sub":"user123","role":"user"}'
# With custom secret
python apileaks.py jwt encode \
'{"sub":"admin","role":"admin","exp":1735689600}' \
--secret mysecretkey
# With custom header
python apileaks.py jwt encode \
'{"sub":"user123"}' \
--header '{"alg":"HS512","typ":"JWT"}' \
--secret strongsecretAPILeak provides advanced JWT security testing capabilities to identify common vulnerabilities.
Test if the server accepts unsigned tokens with alg:none.
python apileaks.py jwt test-alg-none TOKEN [--payload CUSTOM_PAYLOAD]Examples:
# Basic alg:none test
python apileaks.py jwt test-alg-none eyJ0eXAiOiJKV1Q...
# Inject a custom admin payload
python apileaks.py jwt test-alg-none TOKEN --payload '{"sub":"admin","role":"admin"}'
# Validate the attack against a live endpoint
python apileaks.py jwt test-alg-none TOKEN --url https://api.example.com/adminTest null/empty signature bypass techniques.
python apileaks.py jwt test-null-signature TOKEN [--payload CUSTOM_PAYLOAD]Examples:
# Basic null signature test
python apileaks.py jwt test-null-signature TOKEN
# Inject a custom admin payload
python apileaks.py jwt test-null-signature TOKEN --payload '{"sub":"admin","admin":true}'
# Validate against a protected endpoint
python apileaks.py jwt test-null-signature TOKEN --url https://api.example.com/protectedTest the RS256/ES256 → HS256 key-confusion (Substitution) attack: forge a token signed with the
target's public key used as an HMAC secret. Requires --public-key (a PEM/DER file path or
inline PEM). One forged token is produced per public-key representation (PEM ±newline, DER, x5c).
python apileaks.py jwt test-alg-confusion TOKEN --public-key PATH_OR_PEM [--payload CUSTOM_PAYLOAD]# Basic offline forgery from a public key file
python apileaks.py jwt test-alg-confusion TOKEN --public-key server_pub.pem
# Inline PEM material
python apileaks.py jwt test-alg-confusion TOKEN --public-key "$(cat server_pub.pem)"
# Escalate a claim while forging the confused token
python apileaks.py jwt test-alg-confusion TOKEN --public-key server_pub.pem --payload '{"role":"admin"}'
# Validate against a live endpoint
python apileaks.py jwt test-alg-confusion TOKEN --public-key server_pub.pem --url https://api.example.com/adminAttempt to crack weak HMAC secrets using wordlists, then forge a token.
python apileaks.py jwt brute-secret TOKEN [OPTIONS]Options:
--wordlist,-w: Wordlist file (default:wordlists/jwt_secrets.txt)--max-attempts: Maximum attempts (default:1000)-u/--url,-H/--header,-d/--data,--timeout: live-endpoint testing (see above)
Examples:
# Basic secret brute-force
python apileaks.py jwt brute-secret TOKEN
# Use a custom secrets wordlist
python apileaks.py jwt brute-secret TOKEN --wordlist custom_secrets.txt
# Crack the secret and test the forged token against a real endpoint
python apileaks.py jwt brute-secret TOKEN \
--url https://api.example.com/admin \
-H "X-API-Key: key123"Test kid parameter injection (path traversal, arbitrary keys, remote key fetch).
python apileaks.py jwt test-kid-injection TOKEN [--kid-payload PAYLOAD] [--payload JSON]Examples:
# Basic kid injection test
python apileaks.py jwt test-kid-injection TOKEN
# Path-traversal kid payload
python apileaks.py jwt test-kid-injection TOKEN --kid-payload "../../etc/passwd"
# Remote key fetch + custom payload against a live endpoint
python apileaks.py jwt test-kid-injection TOKEN \
--kid-payload "http://attacker.com/key.pem" \
--payload '{"admin":true}' \
--url https://api.example.com/protectedTest JWKS URL (jku) spoofing vulnerabilities.
python apileaks.py jwt test-jwks-spoof TOKEN [--jwks-url URL]Examples:
# Basic JWKS spoofing test
python apileaks.py jwt test-jwks-spoof TOKEN
# Custom malicious JWKS URL
python apileaks.py jwt test-jwks-spoof TOKEN --jwks-url http://attacker.com/jwks.json
# Validate against a live endpoint
python apileaks.py jwt test-jwks-spoof TOKEN \
--jwks-url http://attacker.com/jwks.json \
--url https://api.example.com/protectedTest inline JWKS injection (embed an attacker-controlled public key in the header).
python apileaks.py jwt test-inline-jwks TOKENExamples:
# Basic inline JWKS test
python apileaks.py jwt test-inline-jwks TOKEN
# Validate against a live endpoint with custom headers
python apileaks.py jwt test-inline-jwks TOKEN \
--url https://api.example.com/admin \
-H "X-API-Key: key123"Run all attack vectors (algorithm confusion, secret attacks, injection, payload manipulation) against a live endpoint with baseline comparison and confidence scoring.
python apileaks.py jwt attack-test TOKEN --url URL [OPTIONS]Examples:
# Full automated attack suite against a protected endpoint
python apileaks.py jwt attack-test TOKEN --url https://api.example.com/protected
# With custom headers
python apileaks.py jwt attack-test TOKEN \
-u https://api.example.com/protected \
-H "X-API-Key: key123"
# With POST data for the endpoint under test
python apileaks.py jwt attack-test TOKEN \
-u https://api.example.com/protected \
-d '{"action":"read"}'For comprehensive JWT security testing, use this workflow:
# 1. Decode and analyze the token
python apileaks.py jwt decode $TOKEN
# 2. Test algorithm confusion
python apileaks.py jwt test-alg-none $TOKEN
# 3. Test null signature bypass
python apileaks.py jwt test-null-signature $TOKEN
# 4. Attempt secret brute-force
python apileaks.py jwt brute-secret $TOKEN
# 5. Test kid injection
python apileaks.py jwt test-kid-injection $TOKEN
# 6. Test JWKS spoofing
python apileaks.py jwt test-jwks-spoof $TOKEN
# 7. Test inline JWKS
python apileaks.py jwt test-inline-jwks $TOKEN
# 8. Or run the full automated suite against a live endpoint in one shot
python apileaks.py jwt attack-test $TOKEN --url https://api.example.com/protectedAPILeak can route all of its HTTP traffic (discovery, parameter/header fuzzing, OWASP testing, and the targeted follow-up scan) through an intercepting proxy so that every request and response can be captured, inspected, and replayed in tools like Burp Suite, Caido, or Hetty.
| Option | Description |
|---|---|
--proxy URL |
Send all traffic through the proxy at URL (e.g. http://127.0.0.1:8080). Available on dir, par, and scan. |
--proxy-verify-ssl |
Keep TLS certificate verification enabled while proxying. |
Intercepting proxies terminate TLS with their own certificate authority. To avoid certificate errors against HTTPS targets, TLS verification is automatically disabled when --proxy is set. After installing the proxy's CA certificate in your trust store, pass --proxy-verify-ssl to re-enable verification.
| Tool | Default proxy listener |
|---|---|
| Burp Suite | http://127.0.0.1:8080 |
| Caido | http://127.0.0.1:8080 |
| Hetty | http://127.0.0.1:8080 |
# Directory discovery through Burp Suite
python apileaks.py dir \
--target https://api.example.com \
--proxy http://127.0.0.1:8080
# Authenticated discovery through a proxy (JWT + proxy together)
python apileaks.py dir \
--target https://api.example.com \
--jwt "eyJ0eXAiOiJKV1Q..." \
--proxy http://127.0.0.1:8080
# Parameter fuzzing through Caido
python apileaks.py par \
--target https://api.example.com/users/123 \
--proxy http://127.0.0.1:8080
# Full OWASP scan through Hetty
python apileaks.py scan \
--target https://api.example.com \
--modules bola,auth,ssrf \
--proxy http://127.0.0.1:8080
# Proxy with TLS verification kept on (after installing the proxy CA)
python apileaks.py scan \
--target https://api.example.com \
--proxy http://127.0.0.1:8080 \
--proxy-verify-ssl
# Triage discovery through a proxy, saving a session for later replay
python apileaks.py dir \
--target https://api.example.com \
--proxy http://127.0.0.1:8080 \
--status-code 2xx \
--save-session session.jsonAPILeak supports configuration through environment variables:
| Variable | Description | Default | CLI Equivalent |
|---|---|---|---|
APILEAK_TARGET |
Target URL | - | --target |
APILEAK_LOG_LEVEL |
Logging level | INFO |
--log-level |
APILEAK_RATE_LIMIT |
Requests per second | 10 |
--rate-limit |
APILEAK_MODULES |
OWASP modules | All modules | --modules |
APILEAK_JWT_TOKEN |
JWT token | - | --jwt |
APILEAK_USER_AGENT |
Custom User-Agent | Default | --user-agent-custom |
APILEAK_TIMEOUT |
Request timeout | 10 |
- |
APILEAK_MAX_DEPTH |
Max recursion depth | 3 |
- |
APILEAK_VERIFY_SSL |
Verify SSL certificates | true |
- |
APILEAK_OUTPUT_DIR |
Output directory | reports |
- |
# Set environment variables
export APILEAK_TARGET="https://api.example.com"
export APILEAK_MODULES="bola,auth,property"
export APILEAK_JWT_TOKEN="eyJ0eXAiOiJKV1Q..."
export APILEAK_RATE_LIMIT="5"
# Run scan with environment variables
python apileaks.py scanAPILeak uses specific exit codes to indicate scan results:
| Exit Code | Meaning | Description |
|---|---|---|
0 |
Success | No critical or high severity findings |
1 |
High Severity | High severity vulnerabilities found |
2 |
Critical Severity | Critical vulnerabilities found |
3 |
Scan Error | Scan failed due to technical issues (CI mode only) |
In CI/CD mode (--ci-mode), exit codes are determined by the --fail-on setting. The default is now high (previously critical), so a run without an explicit --fail-on fails on high or critical findings:
# Default gate (high): a plain --ci-mode run fails on high or critical findings
python apileaks.py scan --target URL --ci-mode
# Fail only on critical findings (previous default; still available explicitly)
python apileaks.py scan --target URL --ci-mode --fail-on critical
# Fail on high or critical findings (the new default, stated explicitly)
python apileaks.py scan --target URL --ci-mode --fail-on high
# Fail on medium, high, or critical findings
python apileaks.py scan --target URL --ci-mode --fail-on medium# Quick endpoint discovery
python apileaks.py dir --target https://api.example.com
# Parameter fuzzing with authentication
python apileaks.py par \
--target https://api.example.com/users/123 \
--jwt "eyJ0eXAiOiJKV1Q..."
# Full security scan
python apileaks.py scan \
--target https://api.example.com \
--modules bola,auth,property# WAF evasion with random user agents
python apileaks.py scan \
--target https://api.example.com \
--user-agent-random \
--enable-waf-evasion \
--rate-limit 3
# Framework detection and version fuzzing
python apileaks.py scan \
--target https://api.example.com \
--detect-framework \
--fuzz-versions \
--framework-confidence 0.8
# Comprehensive scan with all advanced features
python apileaks.py scan \
--target https://api.example.com \
--enable-advanced \
--jwt "eyJ0eXAiOiJKV1Q..." \
--output comprehensive-scan# GitHub Actions - SARIF artifact for code scanning, baseline-gated
python apileaks.py scan \
--target ${{ vars.API_TARGET_URL }} \
--jwt ${{ secrets.API_JWT_TOKEN }} \
--ci-mode \
--fail-on critical \
--sarif \
--baseline reports/baseline.json \
--output github-scan-${{ github.run_id }}
# GitLab CI - non-destructive scan that fails on high+ findings
python apileaks.py scan \
--target $API_TARGET_URL \
--jwt $API_JWT_TOKEN \
--ci-mode \
--fail-on high \
--safe-mode \
--sarif \
--output gitlab-scan-$CI_PIPELINE_ID
# Jenkins
python apileaks.py scan \
--target ${API_TARGET_URL} \
--jwt ${API_JWT_TOKEN} \
--ci-mode \
--fail-on critical \
--output jenkins-scan-${BUILD_ID}
# Non-blocking discovery triage in CI (publishes session + Markdown artifacts)
python apileaks.py dir \
--target $API_TARGET_URL \
--status-code 2xx \
--save-session artifacts/session.json \
--export md \
--export-file artifacts/discovery.md \
--interactive \
--ci-mode# Using YAML configuration
python apileaks.py scan --config config/production_api.yaml
# Override config with CLI parameters
python apileaks.py scan \
--config config/base_config.yaml \
--target https://staging-api.example.com \
--modules bola,auth# Decode a JWT token
python apileaks.py jwt decode eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
# Create a test JWT token
python apileaks.py jwt encode \
'{"sub":"testuser","role":"admin","exp":1735689600}' \
--secret testsecret
# Create JWT with custom algorithm
python apileaks.py jwt encode \
'{"sub":"user123"}' \
--header '{"alg":"HS512","typ":"JWT"}' \
--secret strongsecret
# Test JWT security vulnerabilities
python apileaks.py jwt test-alg-none TOKEN
python apileaks.py jwt brute-secret TOKEN --wordlist secrets.txt
python apileaks.py jwt test-kid-injection TOKEN
# Run the full automated JWT attack suite against a live endpoint
python apileaks.py jwt attack-test TOKEN --url https://api.example.com/protected# Debug logging to file
python apileaks.py scan \
--target https://api.example.com \
--log-level DEBUG \
--log-file debug-scan.log
# JSON structured logging
python apileaks.py scan \
--target https://api.example.com \
--json-logs \
--log-file structured.log
# Custom output filename
python apileaks.py scan \
--target https://api.example.com \
--output my-security-audit-2024For more detailed information, see:
- User Guide - Comprehensive usage guide
- Configuration Guide - Configuration file reference
- OWASP Modules Guide - Detailed module documentation
- Docker Usage - Container deployment guide
Re-issue HTTP requests from a prior apileaks scan report (JSON).
apileaks replay REPORT [OPTIONS]
REPORT is the path to a .json report file generated by dir, par, or scan.
| Option | Description | Default |
|---|---|---|
-l, --list |
List all replayable requests — no HTTP issued | false |
-u, --url TEXT |
Filter: only requests whose URL contains this substring | — |
-m, --method TEXT |
Filter: only requests with this HTTP method (e.g. POST) |
— |
--source [endpoint|finding] |
Filter by source section | — |
-i, --index N |
Replay only item N from the filtered list (0-based) | — |
--all |
Replay ALL matching requests (default: first match only) | false |
--proxy URL |
Forward request through Burp/Caido/Hetty | — |
--jwt TOKEN |
Inject Authorization: Bearer TOKEN |
— |
-H, --header Name: Value |
Additional request header (repeatable) | — |
--timeout FLOAT |
Per-request timeout in seconds | 30.0 |
--no-verify |
Disable TLS certificate verification | false |
# List all replayable requests
apileaks replay reports/scan.json --list
# Replay item 3 (0-based) through Burp Suite
apileaks replay reports/scan.json --index 3 --proxy http://127.0.0.1:8080
# Replay all POST findings with a JWT
apileaks replay reports/scan.json --source finding --method POST --jwt eyJ... --all
# Replay every endpoint containing '/admin'
apileaks replay reports/scan.json --url /admin --allDownload, cache, and list Assetnote public wordlists.
Wordlists are cached in ~/.cache/apileaks/wordlists/ and can be used directly in
--wordlist via the assetnote: prefix.
List available Assetnote wordlists (fetches catalogue on first run, cached 24 h).
apileaks wordlist list
apileaks wordlist list --filter apiroutes
apileaks wordlist list --limit 20 --refresh| Option | Description | Default |
|---|---|---|
-f, --filter TERM |
Filter by name/alias substring | — |
--refresh |
Force re-fetch of the catalogue | false |
--limit N |
Maximum entries to display (0 = unlimited) |
50 |
Download and cache a wordlist by alias or filename.
apileaks wordlist fetch apiroutes-210328
apileaks wordlist fetch raft-large-words --refreshShow the local cache directory and its contents.
apileaks wordlist cachePass the assetnote: prefix to --wordlist in dir or par. The wordlist is
auto-downloaded and cached on first use. Append :N to use only the first N lines.
# Auto-download and use the first 20 000 lines of apiroutes-210328
apileaks dir --target https://api.example.com \
--wordlist assetnote:apiroutes-210328:20000
# Use the full apiroutes wordlist
apileaks dir --target https://api.example.com \
--wordlist assetnote:apiroutes-210328All three primary commands (dir, par, scan) and all owasp subcommands
accept a file of targets in place of (or alongside) --target.
| Option | Description | Commands |
|---|---|---|
--target-file FILE |
Plain-text file, one URL per line (# comments and blank lines skipped). Lines without a scheme are auto-prefixed with https:// |
dir, par, scan, all owasp subcommands |
--max-hosts N |
Scan only the first N hosts from the file | same |
# Scan 50 API hosts from a file
apileaks dir --target-file hosts.txt --max-hosts 50
# Combine explicit target + file (explicit target becomes first)
apileaks scan --target https://api.primary.com --target-file others.txt
# Multi-target parameter fuzzing
apileaks par --target-file endpoints.txt --wordlist params.txtHosts are scanned sequentially. A per-host summary table is printed at the end.
When --openapi or --postman is supplied to dir, APILeaks loads the full
operation schema and sends contextually correct requests for each route.
| Option | Description |
|---|---|
--openapi PATH |
OpenAPI/Swagger document (JSON or YAML). Repeatable. |
--postman PATH |
Postman collection (JSON). Repeatable. |
--spec-methods-only |
Probe spec-seeded paths with only the method declared in the spec. Paths from the wordlist continue using --methods as usual. |
# Send per-route query params, headers, and body from spec
apileaks dir --target https://api.example.com --openapi api.yaml
# Strict method matching: only GET where spec says GET, only POST where spec says POST
apileaks dir --target https://api.example.com --openapi api.yaml --spec-methods-onlyHalt discovery early if a host responds positively (non-404) to every path, which typically indicates a wildcard / catch-all configuration.
| Option | Description | Default |
|---|---|---|
--quarantine-threshold N |
Stop after N consecutive non-404 responses. 0 disables. |
0 (disabled) |
# Stop discovery if 10 consecutive hits are returned
apileaks dir --target https://api.example.com --quarantine-threshold 10This complements the existing soft-404 baseline detection, which runs before discovery starts. Quarantine catches wildcard hosts that slip through the initial probes by detecting the pattern during live scanning.