Skip to main content
availability

Deployment: Invicti Platform on-demand
Package: Ultimate
Bundle: API Security

Invicti source scan

Invicti Source Scan generates OpenAPI 3.0 specifications from your application source code and uploads them to Invicti Platform for DAST scanning. It statically analyzes your codebase to discover API endpoints across multiple programming languages — including endpoints that are undocumented, missing from your existing specs, or added since your last spec update.

Use it when:

  • Your team doesn't maintain an OpenAPI spec, or the spec is incomplete.
  • You want to catch shadow APIs and undocumented endpoints before they reach production.
  • You need to keep your API inventory in sync with every code change automatically.

This document explains how to set up and run Invicti Source Scan, upload the generated specification to Invicti Platform, and integrate it into your CI/CD pipeline.

How it works

Invicti Source Scan runs as a Docker container in your CI/CD pipeline or locally:

  1. Scans source code for API endpoint definitions.
  2. Generates an OpenAPI 3.0 specification from discovered endpoints.
  3. Optionally enriches the spec with AI-generated descriptions and examples.
  4. Uploads the specification to Inventory > API catalog for DAST scanning.

Supported languages

The scanner supports the following languages and their popular web frameworks:

Python, JavaScript, TypeScript, C#/.NET, Java, Go, Ruby, PHP, Rust, Kotlin, Swift, Scala, Crystal, Elixir

It also parses existing OpenAPI/Swagger specs and GraphQL schemas.

Prerequisites

  • Docker installed on your machine or CI/CD runner.
  • Invicti Platform credentials: Platform URL, API user email, and API token. You can find the API token under Settings > API tokens.
  • Source code accessible as a local directory or Git repository.
  • Registry access: Log in to the Invicti container registry before pulling the image:
docker login registry.invicti.com

When prompted, enter your Invicti account email as the username and your license key as the password.

Step 1: Run the scan

Mount your source code at /code (read-only) and an output directory at /output:

docker run --rm \
-v "/path/to/your/source/code":/code:ro \
-v "$(pwd)/output":/output \
registry.invicti.com/invicti-platform/invicti-source-scan:latest

The generated OpenAPI spec is saved as output/openapi.json. A typical scan takes between 30 seconds and 2 minutes depending on codebase size and scan profile.

[TODO: Add screenshot of Docker terminal output showing a successful scan with endpoint count]

Example output snippet (openapi.json)
{
"openapi": "3.0.3",
"info": {
"title": "Discovered API - my-service",
"version": "1.0.0"
},
"paths": {
"/api/users/{id}": {
"get": {
"summary": "Get user by ID",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": { "type": "integer" }
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"email": { "type": "string" }
}
}
}
}
}
}
}
}
}
}

Scan options

VariableDefaultDescription
SCANNER_PROFILEstandardquick (deterministic pattern matching only — fastest), standard (adds taint analysis and dataflow graphs), deep (all engines including code property graphs and LLM verification)
SCANNER_PARALLELfalseEnable parallel scanning for large codebases
SCANNER_WORKERS4Number of parallel workers. Only applies when SCANNER_PARALLEL is set to true
SCANNER_SERVICE_NAME-Service name prefix in the OpenAPI spec title
SCANNER_INCREMENTALfalseOnly scan files changed since the last run (faster for CI/CD)
SCANNER_FAIL_ON_CRITICALfalseExit with code 2 if the scan quality gate fails (useful for CI/CD pipelines)

AI-enriched specification (optional)

Enable LLM-powered enrichment to improve the quality of the generated OpenAPI specification. This helps DAST scanners test your API more effectively by providing:

  • Parameter definitions with types, validation rules, and examples — so the DAST scanner can send correctly formatted requests
  • Request/response schemas with property descriptions and required fields — so the DAST scanner can craft valid payloads and detect unexpected responses
  • Authentication schemes detected from decorators and middleware (Bearer, API key, OAuth2) — so the DAST scanner can authenticate before testing protected endpoints

Without enrichment, the scanner still generates a complete OpenAPI spec using deterministic analysis — enrichment refines and extends it.

Enrichment options

Set SCANNER_AI_ENRICH=true and provide an API key. If you're using Anthropic Claude, just set the API key — it's the default provider. Set LLM_PROVIDER only if you want to use a different provider.

VariableDefaultDescription
SCANNER_AI_ENRICHfalseSet to true to enable AI enrichment
LLM_PROVIDERanthropicLLM provider. Set only if not using Anthropic: openai, gemini, or bedrock
ANTHROPIC_API_KEY-Anthropic Claude API key (default provider)
OPENAI_API_KEY-OpenAI API key (requires LLM_PROVIDER=openai)
GOOGLE_API_KEY-Google Gemini API key (requires LLM_PROVIDER=gemini)
AWS_ACCESS_KEY_ID-AWS Bedrock access key (requires LLM_PROVIDER=bedrock)
AWS_SECRET_ACCESS_KEY-AWS Bedrock secret key
SCANNER_MAX_TOKENSunlimitedTotal token budget. When reached, enrichment stops gracefully
docker run --rm \
-v "/path/to/your/source/code":/code:ro \
-v "$(pwd)/output":/output \
-e SCANNER_AI_ENRICH=true \
-e ANTHROPIC_API_KEY=your-api-key \
registry.invicti.com/invicti-platform/invicti-source-scan:latest
note

AI enrichment is optional and does not affect the core scan. If a provider is unavailable or the token budget is exhausted, the scanner falls back to the deterministic-only spec automatically.

Cost and performance

AI enrichment consumes tokens from your LLM provider account. The scanner minimizes costs with a hybrid approach:

  1. Deterministic extraction first — Parameters, status codes, types, and descriptions are extracted directly from source code without any LLM calls.
  2. LLM only where needed — The LLM is called only for endpoints where deterministic confidence is below 70%.
  3. Batch processing — Endpoints are grouped (default: 20 per batch) to reduce API calls. A codebase with 100 endpoints typically requires ~8 LLM calls instead of 140.
  4. Caching — Results are cached per endpoint using a content hash. If the code hasn't changed, cached results are reused with no LLM calls.

As a rough estimate, enriching 100 endpoints costs approximately $0.10–$0.50 in LLM tokens (varies by provider and model). Subsequent scans with caching enabled cost near zero for unchanged endpoints.

Use SCANNER_MAX_TOKENS to set a hard budget — the scanner stops enrichment gracefully when the limit is reached and outputs the spec with whatever enrichment was completed.

Persist the cache in CI/CD

Mount the cache directory as a volume to reuse enrichment results across pipeline runs and avoid repeated LLM costs:

docker run --rm \
-v "/path/to/your/source/code":/code:ro \
-v "$(pwd)/output":/output \
-v "$(pwd)/.enrichment-cache":/.cache/enrichment \
-e SCANNER_AI_ENRICH=true \
-e ANTHROPIC_API_KEY=your-api-key \
registry.invicti.com/invicti-platform/invicti-source-scan:latest
Advanced enrichment configuration

Token budget and rate limiting

VariableDefaultDescription
SCANNER_MAX_TOKENSunlimitedTotal token budget. When reached, the current batch completes and remaining batches are skipped
SCANNER_RPM60Maximum LLM requests per minute
SCANNER_TPM100000Maximum tokens per minute

Caching

VariableDefaultDescription
ENRICHMENT_CACHE_DIR/.cache/enrichmentCache database directory. Mount a volume to persist across runs
ENRICHMENT_CACHE_TTL604800 (7 days)Cache entry time-to-live in seconds
SCANNER_NO_CACHEfalseSet to true to skip cache and force fresh analysis

Batch processing and hybrid analysis

VariableDefaultDescription
ENABLE_BATCHINGtrueGroup endpoints into batches to reduce API calls
OPENAPI_BATCH_SIZE20Number of endpoints per enrichment batch
DETERMINISTIC_CONFIDENCE_THRESHOLD0.7Use LLM only when deterministic confidence is below this value
LLM_MODELprovider defaultOverride the default model for your provider

Example with advanced options

docker run --rm \
-v "/path/to/your/source/code":/code:ro \
-v "$(pwd)/output":/output \
-v "$(pwd)/.enrichment-cache":/.cache/enrichment \
-e SCANNER_AI_ENRICH=true \
-e ANTHROPIC_API_KEY=your-api-key \
-e SCANNER_MAX_TOKENS=500000 \
-e SCANNER_RPM=30 \
-e OPENAPI_BATCH_SIZE=10 \
registry.invicti.com/invicti-platform/invicti-source-scan:latest

Step 2: Upload to Invicti Platform

Add the sync environment variables to automatically upload the specification:

docker run --rm \
-v "/path/to/your/source/code":/code:ro \
-v "$(pwd)/output":/output \
-e INVICTI_SYNC=true \
-e INVICTI_URL=https://platform.invicti.com \
-e INVICTI_USER=your-api-user@company.com \
-e INVICTI_TOKEN=your-api-token \
registry.invicti.com/invicti-platform/invicti-source-scan:latest
VariableRequiredDescription
INVICTI_SYNCYesSet to true to enable upload
INVICTI_URLYesInvicti Platform base URL
INVICTI_USERYesAPI user email
INVICTI_TOKENYesAPI token
DRY_RUNNoSet to true to validate without uploading

Step 3: View and scan imported APIs

  1. Select Discovery from the left-side menu, then go to Inventory > API catalog.
  2. Locate the uploaded specification and link it to a target.
  3. Start a DAST scan to test the discovered endpoints.

[TODO: Add screenshot of Inventory > API Catalog page showing an uploaded source scan spec]

[TODO: Add screenshot showing discovered endpoints linked to a target]

Keep your API inventory up to date

Run Invicti Source Scan in your CI/CD pipeline to automatically update your API inventory on every push.

Output formats

The primary output is the OpenAPI 3.0 specification (output/openapi.json) that gets uploaded to API hub. The scanner also generates a detailed JSON result file with endpoint metadata and statistics.

For CI/CD pipeline visibility, you can optionally enable additional report formats:

VariableOutput fileDescription
(default)output/openapi.jsonOpenAPI 3.0 specification — uploaded to API hub
(default)output/result.jsonFull scan results with endpoint metadata and statistics
SCANNER_SARIF_FILEoutput/results.sarifSARIF 2.1 — for GitHub or other code analysis dashboards
SCANNER_JUNIT_FILEoutput/results.junit.xmlJUnit XML — for CI/CD test result viewers (GitLab, Jenkins, Azure DevOps)

All output files are written to the /output volume mount.

Tracking API changes in CI/CD

To see what API changes occurred in a given build before uploading to API hub, provide the previous OpenAPI spec. The scanner includes a diff in the JSON output (changes field) showing added, removed, and modified endpoints — useful for pipeline logs and code review.

docker run --rm \
-v "/path/to/your/source/code":/code:ro \
-v "$(pwd)/output":/output \
-v "$(pwd)/previous-openapi.json":/previous/openapi.json:ro \
-e PREVIOUS_SPEC=/previous/openapi.json \
registry.invicti.com/invicti-platform/invicti-source-scan:latest

CI/CD integration

GitHub Actions

name: API Discovery Scan
on:
push:
branches: [main]
jobs:
source-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Invicti Source Scan
run: |
docker run --rm \
-v "${{ github.workspace }}":/code:ro \
-v "${{ github.workspace }}/output":/output \
-e INVICTI_SYNC=true \
-e INVICTI_URL=${{ secrets.INVICTI_URL }} \
-e INVICTI_USER=${{ secrets.INVICTI_USER }} \
-e INVICTI_TOKEN=${{ secrets.INVICTI_TOKEN }} \
registry.invicti.com/invicti-platform/invicti-source-scan:latest

GitLab CI

source-scan:
stage: test
image: docker:latest
services:
- docker:dind
script:
- docker run --rm
-v "$CI_PROJECT_DIR":/code:ro
-v "$CI_PROJECT_DIR/output":/output
-e INVICTI_SYNC=true
-e INVICTI_URL=$INVICTI_URL
-e INVICTI_USER=$INVICTI_USER
-e INVICTI_TOKEN=$INVICTI_TOKEN
registry.invicti.com/invicti-platform/invicti-source-scan:latest
artifacts:
paths:
- output/

Troubleshooting

Show all troubleshooting topics
No endpoints found
  • Verify the correct directory is mounted at /code. Check with: docker run --rm -v "/path":/code registry.invicti.com/invicti-platform/invicti-source-scan:latest ls /code
  • Confirm your project uses a supported language.
  • For large route files, increase the file size limit: -e SCANNER_MAX_FILE_SIZE=10
Scan is slow
  • Use SCANNER_PROFILE=quick for faster deterministic-only scanning.
  • Enable parallel mode: -e SCANNER_PARALLEL=true -e SCANNER_WORKERS=8
  • Use incremental scanning in CI/CD: -e SCANNER_INCREMENTAL=true
Upload to Invicti fails
  • Verify INVICTI_URL doesn't have a trailing slash.
  • Confirm the API token is valid and not expired.
  • Test with dry run first: -e DRY_RUN=true
  • Check the container logs for detailed error messages.
Path contains spaces (Windows)

Wrap the volume mount path in quotes:

docker run --rm \
-v "C:/Users/My Name/project":/code:ro \
-v "$(pwd)/output":/output \
registry.invicti.com/invicti-platform/invicti-source-scan:latest

Need help?

Invicti Support team is ready to provide you with technical help. Go to Help Center

Was this page useful?