Scanning
Run inkdex-vuln scan, choose what it looks at and how it reports, and read its findings.
inkdex-vuln scan [DIR] [options]DIR is the repository (the current directory by default). It must have an index (inkdex index), or pass --update to build or refresh it first.
Options
| Option | What it does |
|---|---|
--update | Index the repository (or bring its index up to date) before scanning. |
--library | The repository is a library (a package, a crate, a module): the arguments of its exported functions are treated as input. Implies --update. Needs the Library scan capability. |
--local-sources | Also report flows from the environment, command-line arguments, stdin and local files. Off by default: on a server those are the operator's. |
--no-deps | Do not check dependencies against known vulnerabilities. Nothing about your dependencies leaves the machine for that check. |
--only flows|facts|deps | Only one kind of finding: flows (injections and other data reaching a sink), facts (secrets, crypto, settings, dangerous APIs) or dependencies. |
--verdict proven|verify | Only findings with this verdict. |
--severity critical|high|medium|low | Only findings at least this severe. |
--rule RULE | Only these rules (repeatable, globs: VULN-SQLI, VULN-WEAK-*). |
--path GLOB / --exclude GLOB | Only under, or never under, these paths (repeatable; a directory or a glob: src, src/**/*.py). |
--since REF | Only findings absent at this git revision (origin/main). With --update the revision is indexed when it is not. |
--baseline FILE | Only findings absent from a previous report (--format json or sarif). |
--with-ignored | Also show what .inkdex-vuln.toml and nosec comments ignore. |
--explain | Under each finding, why it is there: its source, route, authentication, confidence and the steps of the flow. |
--format text|json|sarif|markdown | Output format. --json is --format json. In a terminal the text report is in colour. |
-o, --output FILE | Write the report to a file instead of stdout. |
--fail-on critical|high|medium|low | Exit with code 1 when a finding is at least that severe (after the filters). For CI. Default: fail_on in .inkdex-vuln.toml. |
-q, --quiet | Print nothing; rely on the exit code. |
What a finding says
HIGH VULN-SSRF Server-side request forgery (CWE-918, proven)
src/routes.rs:35 in app::routes::fetch
GET fetch (src/routes.rs:33) reaches reqwest::get unsanitized- Severity:
critical,high,medium,low. It starts from the class of the vulnerability and goes one step down when:- the route needs authentication;
- the data comes from a service your code called rather than from a request;
- the scan is a library scan, where it depends on what the caller passes.
- Rule and CWE: the class of the finding. See Findings for every rule.
- Verdict:
proven: the index shows the whole path, from where the data enters to where it acts, with nothing on the way that neutralizes it;verify: likely, but a human should look, for example a weaker flow, a generic secret, or a check known only by its name.
- Place: the file, line and function where it acts (the sink, the secret, the setting).
- Evidence: where the data comes from and what it reaches, in words.
The JSON and SARIF outputs carry more: the route and HTTP method, the steps of the flow, the other sources reaching the same place. See Output formats. In text, --explain prints them under each finding.
One finding in detail
inkdex-vuln finding 3174acf4 # a fingerprint, or its first characters
inkdex-vuln finding app.py:9 # or a placefinding prints everything --explain does, the finding's fingerprint, when its rule says proven, whether it is ignored, and the code: the line of the finding with the lines around it, then the line of every step of the flow.
CRITICAL VULN-CMDI OS command injection (CWE-78, proven)
app.py:9 in app.run
GET /run (app.py:9) reaches os.system unsanitized
confidence: 1.0
route: /run
source_category: http.param
steps:
1. app.py:9 run py.flask.request_param
2. app.py:9 run py.exec.shell_always
fingerprint: 3174acf41cfde2857ce2d244cb0dbe898bc4028b
proven when: a request's data reaches the sink unsanitized (confidence >= 0.8); …
code
app.py
8 | def run():
> 9 | os.system('ls ' + request.args['d'])
10 | return 'ok'inkdex-vuln rules lists every rule with its CWE; inkdex-vuln rules VULN-SQLI also says when one of its findings is proven.
Ignoring findings
A finding you reviewed and accept is ignored by its fingerprint, with a reason, in .inkdex-vuln.toml at the root of the repository. Commit the file: the whole team and the CI then skip it, and it stays ignored when the code moves.
inkdex-vuln ignore fe0b3e72 -r "a checksum, not a password"
inkdex-vuln ignored # what is ignored, and why
inkdex-vuln unignore fe0b3e72A nosec comment on the line of a finding, or on the line above, ignores it too. # nosec VULN-SQLI ignores that rule only.
digest = hashlib.md5(data).hexdigest() # nosec VULN-WEAK-HASHThe scan says how many findings it did not show (not shown: 2 ignored, 1 known before); --with-ignored shows them all again.
The same file holds the defaults you would otherwise repeat:
# .inkdex-vuln.toml
fail_on = "high" # scan's --fail-on when not given
exclude = ["vendor/**", "examples"] # never reported
[[ignore]]
fingerprint = "fe0b3e728f0e1a5abc703f1243819021b20226b0"
rule = "VULN-WEAK-HASH" # rule and at are written by `ignore`, for the reader
at = "sum.py:5"
reason = "a checksum, not a password"What is left out on purpose
- Test code, fixtures and examples, and flows passing through them.
- Generated, vendored and minified files.
- Data that only the operator controls (environment, arguments, local files), unless you pass
--local-sources. - A value checked against a fixed list, or passed through an escaping or validation function inkdex knows, stops being reported for the sinks that check protects.
Fingerprints
Every finding has a fingerprint that does not depend on line numbers: the same finding keeps it when code moves. Use it to track findings across runs, or to remember the ones you reviewed. In SARIF it is the partialFingerprints entry, which GitHub code scanning uses to follow alerts.
Libraries
A library has no route: nobody calls it from outside except its users. --library treats the arguments of its exported functions as input, so a path argument reaching open is reported. Those findings are verify and one step lower: whether it is exploitable depends on what callers pass.
inkdex-vuln scan --library .Dependencies
Unless you pass --no-deps (or your license does not include it), scan also checks the dependencies it found in your manifests and lockfiles against known vulnerabilities. A dependency finding (VULN-DEP) names the package, its version, the advisory and the version that fixes it. It is one step less severe when the dependency is declared but never imported by your code.