Source Code Scanning Sensor
Discover_SourceCode finds cryptography in source code. It parses each file into a syntax tree, matches calls against a catalogue of cryptographic library functions, resolves which algorithm each call actually uses, rates the result, and traces the finding back to the entry point that reaches it.
This is the sensor that answers "where in our code would we have to change something" — the question a migration plan is built from.
Overview and what gets scanned
Languages. C, C++, C#, Go, Java, JavaScript, TypeScript, Kotlin, Objective-C, PHP, Python, Ruby, Rust, Scala and Swift. Kotlin and Scala share the Java library catalogue — the JCE is the JCE whichever JVM language calls it — and Objective-C inherits C's.
How a finding is made. The scan runs in stages, each a fallback for the last.
Library detection. Import, include and using statements are parsed and matched against the library catalogue, establishing which cryptographic libraries are in play in each file.
Call-site matching. Every call in the syntax tree is matched against the function definitions of those libraries. This is where most findings come from, and it is precise: a function is matched because the file imported the library that defines it, not because its name looked cryptographic.
Heuristic fallback. For code that calls crypto without a recognisable import, a looser name-based pass. It can be turned off where false positives matter more than coverage.
Algorithm resolution. A call like Cipher.getInstance(transform) names no algorithm at the call site. The sensor backtracks through variable assignments to find what transform actually holds, so the finding records AES/CBC/PKCS5Padding rather than a variable name. The same machinery resolves property assignments and factory methods in C#.
Rating. Each finding is rated against a policy that knows which primitives are broken. MD5, MD4, DES, RC4, ECB mode, SSL 2.0 and 3.0, RSA below 2048 and 40-bit ciphers rate critical. A hardcoded key or initialisation vector rates critical on its own account. Findings are also classified for post-quantum safety, which is what populates the PQC report.
The call graph. The sensor builds a directed graph from entry points to crypto call sites. This is the difference between "there is an MD5 call in the codebase" and "there is an MD5 call reachable from the payment handler" — and it is what the Source Code Visualizer renders.
What it produces. One document per file with findings, a project summary, and the call graph. Findings are counted per finding rather than per file, so a file with twelve crypto calls contributes twelve units to the dashboards.
What it does not produce. No keys or certificates — a key hardcoded in source is reported as a finding against that source, not catalogued as key material. The scan is static: it reads code, it does not run it, so a code path taken only at run time is reported whether or not it would ever execute.
Prerequisites
Where it runs. Against a directory, a ZIP archive, or a repository it clones. It can run on the platform, on an agent, or in a CI pipeline.
Network access. None for a local directory or archive. For a repository source, outbound HTTPS to the hosting service.
Credentials. None for a public repository or a local path. For a private repository, an access token with read scope on the repositories to be scanned — nothing more. Bitbucket App Passwords additionally need the username they belong to; GitHub and GitLab tokens are used on their own.
Execution models. Platform execution, remote execution on an agent, cloud execution, and off-grid. It is also the sensor behind CI/CD source-code discovery, where it runs against a checkout inside the pipeline.
Configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ExtName | string | Yes | Discover_SourceCode | The sensor name. Set for you by the form. |
source | string | Yes | directory | Where the code comes from: directory, zip, github, github_action or bitbucket. |
path | string | Conditional | — | Path to the directory or archive. Required for directory and zip. |
github_repo | string | Conditional | — | Repository URL. Required for the repository sources. |
branch | string | No | master | Branch or tag to scan. Set this — a repository whose default branch is main scans nothing otherwise. |
github_token | string | No | — | Access token for a private repository. Stored encrypted. |
git_username | string | No | — | Username paired with the token. Needed only for Bitbucket App Passwords. |
local_cache | string | No | — | Keep the clone at this path, so a repeat scan does not clone again. |
project_id | string | No | — | The repository's identity in the inventory. See the warning below. |
origin | string | No | local | A label for where the scan came from. |
exclude_paths | list | No | test directories | Paths to skip. |
snippet_context | integer | No | 4 | Lines of surrounding code kept with each finding. |
max_workers | integer | No | 5 | Files parsed in parallel. |
heuristic | boolean | No | true | Heuristic fallback matching. Turn off to reduce false positives at the cost of coverage. |
no_graph | boolean | No | false | Skip call graph construction. Faster, but the Source Code Visualizer has nothing to draw. |
Set project_id or github_repo, always. The dashboards group source findings by repository, and where neither is set the grouping falls back to the scan's own identifier — which is new on every run. A repository scanned nightly without one is counted as a new repository every night, and the repository count climbs by one a day.
A minimal configuration against a local checkout:
ExtName: Discover_SourceCode
source: directory
path: /srv/src/payments-api
project_id: payments-api
A realistic configuration against a private repository:
ExtName: Discover_SourceCode
source: github
github_repo: https://github.com/corp-example/payments-api
branch: main
github_token: "<read-scope token>"
project_id: payments-api
local_cache: /var/cache/cbom/payments-api
exclude_paths:
- test
- tests
- vendor
- node_modules
- third_party
max_workers: 8
snippet_context: 6
Scoping. exclude_paths is the control that matters. Vendored dependencies and test fixtures are usually the bulk of a repository's crypto findings and rarely the ones you act on — a test that hardcodes an AES key is not the same risk as a handler that does. Exclude them, and scan dependencies separately if you want them in the inventory, so the two sets of findings stay distinguishable.
Execution modes
From the portal. Add the sensor to a discovery template, set the source and credentials, assign the template to a task and run it. Findings appear in the crypto inventory and in the Source Code Visualizer.
On an agent. The usual mode for a repository the platform cannot reach, or a checkout that already exists on a build host.
In a CI pipeline. A separate, single-shot path: one scan against the checkout, returning a verdict the pipeline can gate on. It has its own exit codes and its own local ruleset, and it is covered in the CI/CD discovery material rather than here. Two things carry over from this page: set the repository key explicitly, and understand that a scan of only the changed files would make the dashboard report the repository as containing only those files.
Off-grid. Fully supported against a directory or archive.
A source scan replaces its repository's previous result. Every widget narrows to the newest scan per repository, so a partial scan does not add to the last full one — it becomes the repository's answer. Scan the whole tree each time, or accept that the dashboard describes only what the last scan covered.
Known limitations
| Limitation | Effect |
|---|---|
| Static analysis | Code is read, not run. A call reachable only under a configuration never used in production is still reported. |
| Dynamic dispatch | An algorithm name assembled at run time, read from configuration, or passed through a framework the sensor does not model cannot always be resolved. The finding is still recorded; the algorithm may be unresolved. |
| Heuristic matching | With heuristic on, a function whose name resembles a crypto API may be matched without a supporting import. This is the trade-off the switch exists for. |
| Generated code | Scanned like any other source, so a large generated file can dominate a repository's finding count. Exclude generated directories. |
| Language coverage | A file in a language not in the list is skipped. It is not reported as having no crypto — it is not examined. |
| Dependencies | Only the source in the scanned tree is examined. Crypto inside a package pulled from a registry is found by the binary sensor, not this one. |
| Ambiguous C headers | A .h file may be C or C++. It is resolved by content rather than extension, which is right almost always and occasionally not. |
Troubleshooting
The scan found nothing in a repository you know uses crypto. Check branch first — this is the most common cause by a wide margin, since the default is master and most repositories now use main. Then check exclude_paths has not excluded the source tree.
The repository count keeps growing. project_id and github_repo are both unset, so each run is counted as a new repository. Set one and the previous entries can be retired.
Clone fails with authentication required. For a private repository the token must have read scope on that repository, and for Bitbucket App Passwords git_username must be set as well. A token that works for git clone from a terminal works here.
Far more findings than expected. Vendored dependencies or test fixtures are in scope. Add them to exclude_paths.
Findings have no algorithm. The algorithm is set at run time and backtracking could not resolve it. The call site is still correct, and the snippet shows what was being called. Raise snippet_context to see more of the surrounding code.
The Source Code Visualizer shows nothing. no_graph is on, so no call graph was built. Turn it off and re-scan.
The scan is slow on a large repository. Raise max_workers, exclude more aggressively, and turn off no_graph only if the visualizer is not needed — graph construction is a real share of the time on a large tree.
Getting support
Collect the platform version, the sensor configuration with the token removed, the task and template names, the repository's language mix and approximate size, and the discovery log extract. Where a specific finding is wrong, the single most useful thing to include is the few lines of source it points at, together with what you expected the algorithm to resolve to. Never include the access token.