Scanning
What each scanner looks for, how scans are triggered, and what a scan costs.
You will finish this page knowing exactly what Argus inspects, what each engine can and cannot see, and how to run a scan from the UI, the API, or an AI coding assistant.
What a scan does
Every Argus scan clones your repository at the target branch, runs the engine set, posts results back, and deletes the clone.
Ordered phases:
- Shallow clone of the branch
- SAST: source-code analysis
- SCA: dependency advisories from lockfiles
- Malicious package / typosquat screening
- Secrets: three independent detection passes
- Kubernetes / Helm misconfiguration
- IaC: Terraform, CloudFormation, Azure ARM, Dockerfile
- Container: CVEs in base images referenced by your Dockerfiles
- Reachability: is each vulnerable dependency actually imported?
- API discovery: routes your code exposes, and third-party services it calls
- BOM generation: SBOM and the specialised BOMs
- Deduplication and noise filtering
- AI passes (when AI scanning is enabled), triage, secret validation, taint, business-logic, LLM-application, race-condition, threat model, adversarial verification
- Author attribution via
git blame - Results posted back to Argus and reconciled with the previous scan
The clone is deleted when the scan finishes.
Engines in detail
SAST, your source code
Argus runs Semgrep with the auto-resolved registry ruleset, so language coverage follows Semgrep's registry rather than a fixed allowlist. Each result is re-scored using the rule's own security-severity metadata, then enriched with a remediation suggestion and a MITRE ATT&CK technique where one maps.
When AI scanning is enabled, additional passes look for classes that pattern rules miss:
| Pass | Looks for | File types |
|---|---|---|
| Taint analysis | Source-to-sink data flow | .py .js .ts .rb .go .java .php |
| Business logic | IDOR, privilege escalation, auth bypass, broken sequences, unsafe API chains | .py .js .ts .rb |
| LLM application | OWASP LLM Top 10, prompt injection, insecure output handling, excessive agency, and related classes | .py .js .ts containing LLM SDK usage |
| Race conditions | TOCTOU, double-spend, transaction-scope errors | .py .js .ts .go .java |
Every AI-generated finding then goes through an adversarial verification pass: independent jurors attempt to refute the finding, and unsupported ones are dropped.
Test files are skipped by default. A test that asserts on a dangerous pattern has to contain that
pattern, so a TLS test trips a TLS rule and a SQL-injection test trips a SQL rule. Argus recognises
the usual conventions (*.test.*, *.spec.*, __tests__/, tests/, test_*.py, *_test.go,
conftest.py) and reports how many findings it excluded rather than quietly shrinking the number.
SCA, your dependencies
Argus parses lockfiles and queries OSV.dev for advisories affecting the exact installed versions. CVSS base scores are computed from the advisory's own vector string.
| Lockfile | Ecosystem |
|---|---|
package-lock.json, yarn.lock, pnpm-lock.yaml | npm |
requirements.txt, requirements-dev.txt, Pipfile.lock | PyPI |
go.sum | Go |
Gemfile.lock | RubyGems |
Cargo.lock | crates.io |
composer.lock | Packagist |
node_modules, vendor, venv, .git and __pycache__ are skipped.
Java and .NET: Argus does not parse
pom.xml, Gradle files,.csprojorpackages.lock.json. Java and .NET packages are still inventoried through container scanning and the SBOM generator, but they are not matched against advisories by the SCA engine.
Malicious packages and typosquats
Two independent checks run over the dependency list:
- Malicious package advisories. Every dependency is checked, version-scoped, against OSV's malicious-package feed. A hit is a
CRITICALfinding. - Typosquat / slopsquat detection. Package names are compared against a curated table of popular npm, PyPI, Go and RubyGems names using edit distance. A name exactly one edit away from a popular package, and not the package itself, is flagged
MEDIUM. This catches both classic typosquats and slopsquats: lookalike or non-existent package names that AI coding assistants hallucinate.
The same logic backs the scan_package MCP tool, so an AI assistant can get a verdict before it runs npm install. See Integrations.
Secrets
Three sequential passes, each skipping locations an earlier pass already reported:
- Gitleaks: the vendor pattern library for known credential formats.
- Entropy analysis: base64/base64url tokens 20-120 characters at ≥ 4.3 bits/char, and hex strings 32-128 characters at ≥ 3.0 bits/char.
- Named assignment: a quoted literal assigned to a credential-named identifier (
api_key,client_secret,private_key,session_secret, and similar), where the value is at least 8 characters and is not a URL, path, git SHA, placeholder or environment reference.
Known-noise sources are filtered out before anything is reported: test and fixture paths, documentation placeholders (such as the AWS example key), publishable keys (pk_, pub_), bare environment-variable names, environment references (process.env.X, ${VAR}, os.getenv), git SHAs, subresource-integrity hashes, every lockfile, and *.example.* / *.sample.* / *.template.* files.
With AI scanning enabled, each secret is additionally classified for validity: Live, Rotated, Test, or Unknown.
IaC and Kubernetes
Trivy config scans Terraform, Terraform plans, CloudFormation, Azure ARM and Dockerfiles; a second pass covers Kubernetes manifests and Helm charts. Both emit IaC findings; Kubernetes results are prefixed K8s:.
Container base images
Argus finds Dockerfiles by name (Dockerfile, Dockerfile.prod, api.dockerfile, …), reads their FROM lines, and scans each referenced image with Trivy. No Docker daemon and no local build is needed. The image is pulled directly from its registry.
scratch, multi-stage local stage references, and refs built from build args (${VAR}) are skipped.- Up to 3 distinct images per repository.
- Only CVEs with an available fix are reported. Unfixed base-OS noise is suppressed.
- Both OS packages and application packages inside the image are covered, with layer attribution.
- Results are
SCAfindings located at the Dockerfile.
API discovery
Argus extracts the HTTP routes your code defines and the third-party domains it calls. These populate the API inventory and third-party inventory rather than the findings list. See Supply chain.
API DAST, optional, opt-in
Argus can actively probe a running API. This is deny-by-default: it requires an explicit base URL and a non-empty host allowlist, and only issues GET, HEAD and OPTIONS unless you explicitly permit mutating methods. Results are DAST findings.
Standard vs Deep Agentic
The tier controls whether an autonomous AI agent additionally explores the repository.
| Standard | Deep Agentic | |
|---|---|---|
| SAST, SCA, Secrets, IaC, K8s, Container | Yes | Yes |
| Reachability, API discovery, BOMs | Yes | Yes |
| AI triage, taint, logic, LLM, race, threat model | When AI scanning is enabled | When AI scanning is enabled |
| Autonomous exploration agent | - | Yes |
| Credits | 3 | 10 |
| Scan type shown in the UI | Full Scan | Deep Agentic (AI-Powered) |
The Deep Agentic tier runs an AI agent with read-and-search access to the cloned repository. It follows its own hypotheses across files and reports what it can substantiate, then its findings pass through the same adversarial verification as every other AI finding.
Deep Agentic findings are tagged as their own category. A later standard scan will not resolve them away, because reconciliation only touches the categories a scan actually covered.
Running a scan
From the UI
- Open Projects.
- On the project card, click Scan ›. The Start scanning project dialog opens.
- Under Vulnerability types to scan for, tick
SAST,SCAand/orSECRET. - Under SAST Scan Depth, choose Standard Scan (
3 credits) or Deep Agentic Scan (AI,10 credits). - Click Start Scan (or Start Deep Scan). You will see
Scan queued for <project>. - Watch progress on Scan Jobs.
If your balance cannot cover a Deep Agentic scan, the submit button is replaced by Add credits and the dialog tells you the shortfall.
From the API
curl -sS -X POST "$ARGUS_URL/api/graphql" \
-H "Authorization: Bearer argus_live_xxx" \
-H "content-type: application/json" \
-d '{
"query": "mutation Scan($p: ID!, $d: String) { TriggerScan(projectId: $p, scanDepth: $d) { id status scanType } }",
"variables": { "p": "<project-id>", "d": "standard" }
}'
scanDepth accepts standard (default) or deep_agentic.
Poll for completion:
curl -sS -X POST "$ARGUS_URL/api/graphql" \
-H "Authorization: Bearer argus_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"{ listScanJobs(limit: 5) { id projectName status scanType findings startedAt finishedAt duration } }"}'
From an AI coding assistant
With the Argus MCP server connected, an assistant can run trigger_scan and poll list_scans directly. See Integrations.
Scan triggers
| Trigger | How it fires |
|---|---|
| Manual | You start it from Projects, the top bar, or the API |
| Pull-request merge | Argus scans the target project automatically when a pull request merges |
| MCP | An AI assistant calls trigger_scan |
| CI | Your pipeline calls the diff scanner on each pull request, see Pull request security |
Scheduled scans are coming soon. Do not rely on a recurring schedule today; drive periodic scans from your own CI cron or from the API.
Tracking a scan, the Scan Jobs page
Scan Jobs lists every run. Each row shows the project, branch and commit, a live progress bar with an estimated time remaining, the status, the finding count, the duration, and the scan-type chip. Failed rows carry an inline Retry.
| Job status | Meaning |
|---|---|
Queued | Accepted, waiting for a worker |
Pending | Created, not yet dispatched |
Running | In progress |
Completed | Finished; results ingested |
Failed | Did not complete. The credit charge is refunded |
Filter by Scan Type (SAST, SCA, Secret, IaC, Container) and Status. Search across project, branch and commit. 20 jobs per page.
Completed jobs carry coverage chips: {n} SAST, {n} SCA, {n} Secrets, {n} Verified, and Deep Agentic when that tier ran, plus per-phase timing chips.
Open a job to see its Details: scan type, who triggered it, branch, commit, start and finish times, elapsed, and finding count. Failed jobs show the error. When AI scanning ran, an AI Scan Results card reports findings kept, false positives filtered, the estimated AI cost and the model used.
The Timeline and Live logs views on a scan job are not yet available and do not show recorded execution data. Use the Details view, the coverage chips, and the Issues workspace instead.
Reading scan results
A completed scan writes:
- Findings, reconciled against the previous scan of the same categories
- Dependencies, with vulnerability counts and license data
- API endpoints and third parties
- BOMs: SBOM plus any specialised BOMs that had content
- Author attribution for each finding, via
git blame
Findings a re-scan no longer reports are set to Resolved automatically. Findings that reappear are reopened.
If a scan fails, its credit charge is refunded and the rule-scan slot it consumed is returned.
Scanning without giving us your code
If your organisation will not grant repository access, you can still be scanned. Generate an SBOM with your own tooling and upload the document, Argus never clones, never reads your source, and never builds your project.
What you need
A CycloneDX 1.x or SPDX 2.x JSON document with a package URL (purl) on each component. The common
generators emit purls by default:
syft dir:. -o cyclonedx-json > sbom.json # any language
cdxgen -o sbom.json # any language
npm sbom --sbom-format cyclonedx > sbom.json # npm projects
What you get
Every component is checked against the same vulnerability sources a full scan uses, OSV advisories and our malicious/typosquat package checks. A finding here is the same finding a full scan would produce for that component, not a reduced one.
What you do not get, and why
An SBOM is a list of components. It contains no files, no line numbers and no call graph, so these engines cannot run at all:
| Engine | Available from an SBOM? |
|---|---|
| Dependency vulnerabilities (SCA) | ✅ Yes |
| Malicious / typosquatted packages | ✅ Yes |
| Static analysis (SAST) | ❌ Needs source |
| Secret detection | ❌ Needs source |
| IaC misconfiguration | ❌ Needs source |
| Reachability | ❌ Needs a call graph |
Argus reports these as not assessed rather than as zero. A scan that showed "0 secrets found" when it never looked for secrets would be worse than no answer at all, so we do not show one.
Running the full engine inside your own network
If you want SAST, secret detection and IaC checks, not just dependencies, but still nothing may leave your perimeter, run the scanner yourself and send only the results.
ARGUS_API_KEY=argus_live_... ARGUS_PROJECT_ID=<id> ./argus-local-scan.sh .
The script runs the scanner container with --network none, so it cannot reach any network while
it reads your code. That guarantee is enforced by Docker, not promised by us. It then prints
exactly what is about to be sent (finding counts, dependency counts, categories) before sending it,
and refuses to upload a payload containing file contents.
What travels: findings, dependency names and versions, and the commit SHA. What does not: your source.
Two honest limitations:
- Dependency advisories are resolved on our side. Looking up a CVE requires reaching the OSV
database, which a
--network nonecontainer cannot do. Your runner sends the dependency list, package names and versions, the same facts an SBOM carries, and Argus resolves advisories from it. - A category only counts if its engine actually ran. If
semgrepis missing from your image, the runner reports SAST as not scanned rather than as clean. This matters: Argus auto-closes findings in categories a scan covered, so a run that claimed SAST without running it would silently resolve your real SAST findings.
Accuracy note. Your results are exactly as complete as your SBOM. If your generator omits transitive dependencies, or omits purls for some components, those components are not scored, Argus tells you how many components it could and could not use, and a document with no usable purls is rejected with an explanation rather than accepted as an empty, clean-looking result.
Limits worth knowing
| Limit | Value |
|---|---|
| Container images scanned per repository | 3 |
| Secret findings per pass | 60 |
| Advisories reported per package | 25 |
| Source files walked for reachability | 8,000 |
| Files skipped by size (secrets) | > 1 MB |
Every engine degrades gracefully: if a tool is unavailable, that engine returns nothing and the scan still completes with the remaining engines.
Next
- Issues and remediation, triage what a scan found
- Pull request security, shift the same engines left
- Supply chain, dependencies, BOMs and VEX