Security review starts with a question: can untrusted input reach a dangerous operation, can a permission check be bypassed, or does a known weakness apply to this code? Answering it requires entry points, connections and execution conditions. A suspicious fragment alone does not explain how the problem would occur in the application.
CodeGraph turns these assumptions into hypotheses and checks them against the Code Property Graph (CPG). A hypothesis defines the question; the graph helps investigate program structure and available relations. The workflow uses a knowledge base and registered pattern providers. Each checked hypothesis is confirmed, rejected or inconclusive.
The team receives evidence for investigation: what was checked, which queries ran, which assumptions were supported and where evidence was insufficient. This helps focus manual review on specific code locations. Engineers use the source locations and query evidence to examine exploitability conditions and prepare a security test.
From an assumption to a check
Consider a teaching question: can a value from an HTTP request affect an SQL query? The reviewer selects relevant hypotheses and a repository revision. The workflow then queries the CPG within the chosen scope. The engineer compares the resulting locations with source code and checks parameterization, data transformations and other conditions that affect the risk.
If graph relations are insufficient, the result remains inconclusive and identifies a need for further investigation. After a fix, the team rebuilds the graph and repeats the check under the same conditions. Comparing the results shows how the fix affected the data path under review.
When to use this analysis
- Review a sensitive change by investigating selected hypotheses for the intended revision.
- Investigate a known weakness using supported category or CVE filters.
- Prepare execution checks by exporting supported fuzz or DAST targets.
- Hand results to AppSec with the report, scope, exclusions and source locations.
Connecting hypotheses to a graph turns a general warning into a question that can be checked against code. Use the analysis capability map to select checks for your language and framework, then add adjacent checks: hypotheses examine code weaknesses, threat modeling examines system boundaries, and SCA/SBOM examines dependencies.
Choose an interface
Use the CLI for local, explicit CPG files, detailed filters, incremental runs, report files, and fuzz-target export. Use MCP when an authorized agent session already has project context and needs a typed analysis result.
See the CLI guide for command options and the
MCP operator guide to connect an agent session.
Use codegraph_security_hypothesis_run through MCP. For automation, use the selected
command’s --help output or the MCP tool schema in your installed version.
Run from the CLI
Install the CLI using the CLI guide. Run these Bash commands
from the CodeGraph repository root. The current executor requires an accessible GoCPG gRPC
service. --db selects the CPG; it does not enable direct DuckDB access.
export CODEGRAPH_ALLOW_LOCAL_PYTHON_CLI=1
python -m src.cli hypothesis run --db "<cpg-path>" --human-language en
Select language, volume, priority, and output explicitly when reproducibility matters:
python -m src.cli hypothesis run \
--db "<cpg-path>" \
--language C \
--max 50 \
--min-priority 0.5 \
--format json \
--output "hypothesis-report.json" \
--human-language en
The JSON report includes the batch identity, execution counts, result counts, timing, and bounded hypothesis fields. Preserve the indexed Git revision and command arguments beside the report.
Parameters for a regular run select what to check and how much to return:
| Parameter | How to choose a value | Default |
|---|---|---|
--language |
Set the source language, such as C. |
C |
--max |
Set the maximum number of hypotheses in the batch. | 50 |
--min-priority |
Set the minimum hypothesis priority for validation. The example uses 0.5. |
0.3 |
--category |
Select a weakness category; repeat the flag for multiple categories. | No category filter |
--format |
Choose json for programmatic processing or text for terminal output. |
text |
--human-language |
Choose the explanation language: ru or en. |
en |
Keep the same filters and threshold when comparing two revisions. This lets you relate a change in confirmed hypotheses to the code change demonstrated below.
Check a change with a worked example
In this example, a function reads text from an environment variable through getenv
and passes it to system. The command-injection hypothesis checks for the input source
and command execution within that function. We then replace command execution with
text output through puts, rebuild the graph and compare the results.
Run these Bash commands from the CodeGraph repository root. Set GOCPG_BIN to the
absolute path of your installed GoCPG executable in place of <path-to-gocpg>;
on Windows, use the gocpg.exe file. You also need an accessible GoCPG gRPC service,
as for the preceding commands. Replace <new-demo-dir> with a new directory for the
example sources, graphs and reports. Parse the teaching source with the analyzer;
you do not need to compile or execute it to check the hypothesis.
Create the source, build its CPG and save the report:
GOCPG_BIN="<path-to-gocpg>"
DEMO_DIR="<new-demo-dir>"
mkdir -p "$DEMO_DIR/before"
cat > "$DEMO_DIR/before/example.c" <<'C'
#include <stdio.h>
#include <stdlib.h>
void run_action(void) {
char *command = getenv("CODEGRAPH_DEMO_COMMAND");
if (command != NULL) {
system(command);
}
}
C
"$GOCPG_BIN" parse --input "$DEMO_DIR/before" \
--output "$DEMO_DIR/before.duckdb" --lang c
export CODEGRAPH_ALLOW_LOCAL_PYTHON_CLI=1
python -m src.cli hypothesis run \
--db "$DEMO_DIR/before.duckdb" \
--language C --category command_injection \
--max 50 --min-priority 0.5 --format json \
--output "$DEMO_DIR/before.json" --human-language en
Open <new-demo-dir>/before.json. For this source, expect one executed check
(executed_queries: 1) and one confirmed hypothesis (confirmed_hypotheses: 1)
in category command_injection. Its cwe_ids include CWE-78. In the source,
follow command from getenv to system: this is the code the team receives for review.
Replace system(command) with puts(command) and keep the new version separately.
Rebuild the CPG and repeat the same check:
mkdir -p "$DEMO_DIR/after"
sed 's/system(command);/puts(command);/' \
"$DEMO_DIR/before/example.c" > "$DEMO_DIR/after/example.c"
"$GOCPG_BIN" parse --input "$DEMO_DIR/after" \
--output "$DEMO_DIR/after.duckdb" --lang c
python -m src.cli hypothesis run \
--db "$DEMO_DIR/after.duckdb" \
--language C --category command_injection \
--max 50 --min-priority 0.5 --format json \
--output "$DEMO_DIR/after.json" --human-language en
In <new-demo-dir>/after.json, expect executed_queries: 1,
confirmed_hypotheses: 0 and rejected_hypotheses: 1. The number of checks stays
the same, while the command-injection hypothesis becomes rejected: the new version
prints the value as text through puts. The two sources, graphs and reports let the
reviewer inspect both the change and its repeated check.
Limit the scope
A regular run applies repeatable --category and comma-separated --cve arguments.
The parser accepts run --cwe, but the current handler does not use it.
For export, --cwe filters already validated hypotheses for export; it does not limit queries.
--incremental --base-ref "<git-ref>" compares that revision with HEAD in the current
working directory. It excludes uncommitted changes. This mode ignores --category, --cwe,
--cve, and all exclusion arguments. An empty changed-file list triggers full validation.
A Git diff failure can also produce an empty list. Check the baseline and changed-file list
separately before starting this mode.
For regular run and export, use --exclude-fixtures, --exclude-mocks, --exclude-generated, or repeatable
--exclude-category when those inputs are outside the assessment. Record exclusions with the report
to identify the scope of the assessment.
Before analysis, update the CPG for the repository revision being assessed and pass its path
through --db.
Inspect coverage and export targets
List the available knowledge-base entries and registered providers before choosing filters:
python -m src.cli hypothesis list-cwes --format json
python -m src.cli hypothesis providers
A provider groups analysis patterns for a language or framework, data sources, and
sensitive operations. The providers command shows its contents: Patterns counts
patterns, Sources counts data sources, and Sinks counts sensitive operations.
Use this list to choose a provider for your project. The list-cwes command shows
weakness categories in the knowledge base and helps you choose what to investigate.
Export supported fuzzing or DAST targets with an explicit database and output directory:
python -m src.cli hypothesis export \
--db "<cpg-path>" \
--format generic \
--output "fuzz_targets" \
--human-language en
The export command runs validation, selects hypotheses by priority and the optional CWE filter,
then writes targets.json and files for each target. The manifest includes entry and sink
functions, input hints, CWE identifiers, priority and the hypothesis text. Source locations come
from the collected evidence; function names can also come from the hypothesis’s source and sink
patterns.
The generic format writes a JSON description for each target. The afl and libfuzzer formats
write seed inputs and harness stubs. Hypotheses for supported web weaknesses also produce Nuclei
templates. Connect each harness to the application entry point, configure its build and inputs,
and run it in a sandbox. Use the validation report to choose which hypotheses to investigate first.
Run through MCP
Use the AppSec read connection with profile codex:role:codegraph_appsec:read, then select
codegraph_security_hypothesis_run in the client. The tool accepts an action of
run, list_cwes, or list_providers, plus supported language, volume, priority, category, and
human-language fields.
To list provider names and their languages, pass this object to the tool:
{"action": "list_providers"}
For run, the MCP tool selects the CPG from the authorized project’s runtime context.
Select the project in the client before starting analysis.
For setup and typed-call rules, use the MCP operator guide.
Interpret results
| Result | What the check established | Next action |
|---|---|---|
| Confirmed | Evidence satisfies the current validation rules. | Open the source locations and examine the data path and execution conditions. |
| Rejected | The evaluated hypothesis did not meet these rules. | Keep the result with the check scope and revision for comparison with a later run. |
| Inconclusive | The available graph or evidence could not settle the hypothesis. | Identify the relations or data needed to continue the check. |
The current metrics calculation counts each confirmed hypothesis as a true positive (true_positives).
Missed explicitly requested CVEs increase false_negatives; false_positives retains its initial
value of 0. Values for precision, recall and f1_score are calculated from these counters
and describe the current run’s results.
When reviewing a finding, open its source locations, query evidence, category and CWE mapping.
To assess exploitability, follow the data path and execution conditions, then reproduce the
behavior with an appropriate security test.
Work with findings
Language patterns define the constructs to check, and the CPG supplies relations between code elements. Engineers use hypothesis evidence to select code for review and prepare a test. After a fix, refresh the graph and rerun the same hypothesis check.
Run generated fuzz targets in a sandbox after reviewing their code and build settings. Keep reports in the team’s designated storage with access for reviewers: they contain repository structure and details of identified weaknesses.
Use threat modeling for system-level trust boundaries and SCA/SBOM for dependency risk; the three workflows answer different questions.