mirror of
https://github.com/usestrix/strix.git
synced 2026-08-24 03:42:37 +02:00
reporting: require the source-to-sink trace in reachability evidence, not just CVSS reasoning
This commit is contained in:
@@ -161,7 +161,23 @@ fi
|
|||||||
verdict/evidence onto its siblings; run the symbol search against each
|
verdict/evidence onto its siblings; run the symbol search against each
|
||||||
CVE's own affected-symbol list. The import check (step 1) is the only
|
CVE's own affected-symbol list. The import check (step 1) is the only
|
||||||
part shared across a package's CVEs.
|
part shared across a package's CVEs.
|
||||||
3. If the analysis was not performed or is inconclusive (obfuscated code,
|
3. **Source-to-sink trace — do this whenever step 2 found a symbol hit.** A
|
||||||
|
symbol hit alone says the code calls the vulnerable API; it does not say
|
||||||
|
who can reach it. Start at the sink (the exact line that calls the
|
||||||
|
vulnerable function) and walk backwards hop by hop to the source: the
|
||||||
|
entry point that carries untrusted input (HTTP route, CLI argument, queue
|
||||||
|
or webhook payload, uploaded file, config value). Read each intermediate
|
||||||
|
function; when a hop is a thin wrapper, go one step deeper — never stop at
|
||||||
|
the first caller. Record what each hop enforces: authentication, a role
|
||||||
|
check, validation, a feature flag, a size or type limit, a default that is
|
||||||
|
off in production.
|
||||||
|
Write the chain into `reachability_evidence` as
|
||||||
|
`entry point -> intermediate call -> package call` with a
|
||||||
|
repository-relative `file:line` for every hop, and say who controls the
|
||||||
|
input. If no source reaches the sink, say that too — the level stays
|
||||||
|
`vulnerable_symbol_used` (the call is real), and the trace is what tells
|
||||||
|
the reader it is only reachable from, say, an operator CLI.
|
||||||
|
4. If the analysis was not performed or is inconclusive (obfuscated code,
|
||||||
dynamic loading, unparsable sources) ⇒ `unknown` and say why in
|
dynamic loading, unparsable sources) ⇒ `unknown` and say why in
|
||||||
`assumptions`.
|
`assumptions`.
|
||||||
|
|
||||||
@@ -258,24 +274,15 @@ Set only what your usage analysis supports:
|
|||||||
- `CR`/`IR`/`AR` `H`/`M`/`L` — the security requirement of the data or service
|
- `CR`/`IR`/`AR` `H`/`M`/`L` — the security requirement of the data or service
|
||||||
the package handles (credentials or payment data raise `CR`).
|
the package handles (credentials or payment data raise `CR`).
|
||||||
|
|
||||||
Ground every metric in a **source-to-sink trace**, not in a general impression
|
Ground every metric in the **source-to-sink trace** from the usage analysis
|
||||||
of the package. Before you set any metric:
|
(step 3 above), not in a general impression of the package. Derive the metrics
|
||||||
|
from that chain: `MAV`, `MPR`, and `MUI` come from what the source requires;
|
||||||
|
`MAC` comes from the preconditions the hops enforce; `MC`, `MI`, and `MA` come
|
||||||
|
from the data and privileges available at the sink; `CR`, `IR`, and `AR` come
|
||||||
|
from what that data is worth.
|
||||||
|
|
||||||
1. Find the sink: the exact line where this codebase calls the vulnerable
|
No trace, no contextual metrics: if you did not reach a symbol hit, or you
|
||||||
function or class of the package.
|
could not follow a hop, omit the contextual fields instead of guessing.
|
||||||
2. Walk backwards hop by hop to the source: the entry point that carries
|
|
||||||
untrusted input (HTTP route, CLI argument, queue or webhook payload,
|
|
||||||
uploaded file, config value). Read each intermediate function. When a hop
|
|
||||||
is a thin wrapper, go one step deeper — never stop at the first caller.
|
|
||||||
3. Record what each hop enforces: authentication, a role check, validation, a
|
|
||||||
feature flag, a size or type limit, a default that is off in production.
|
|
||||||
4. Derive the metrics from that chain. `MAV`, `MPR`, and `MUI` come from what
|
|
||||||
the source requires. `MAC` comes from the preconditions on the hops. `MC`,
|
|
||||||
`MI`, and `MA` come from the data and privileges available at the sink.
|
|
||||||
`CR`, `IR`, and `AR` come from what that data is worth.
|
|
||||||
|
|
||||||
If the chain breaks — no source reaches the sink, or you cannot follow a hop —
|
|
||||||
say so and omit the contextual fields instead of guessing.
|
|
||||||
|
|
||||||
`contextual_cvss_reasoning` is required with the metrics. Write two to four
|
`contextual_cvss_reasoning` is required with the metrics. Write two to four
|
||||||
sentences that another engineer can check without opening the repository. Name
|
sentences that another engineer can check without opening the repository. Name
|
||||||
|
|||||||
@@ -1188,6 +1188,17 @@ async def create_dependency_report(
|
|||||||
(required for any level other than ``unknown``): repo-relative
|
(required for any level other than ``unknown``): repo-relative
|
||||||
``file:line`` of the import or symbol usage, the matched
|
``file:line`` of the import or symbol usage, the matched
|
||||||
advisory symbols, or the govulncheck call-path excerpt.
|
advisory symbols, or the govulncheck call-path excerpt.
|
||||||
|
Whenever you found the vulnerable symbol in use, also give the
|
||||||
|
**source-to-sink trace** here: start at the vulnerable package
|
||||||
|
call site and walk backwards hop by hop to the entry point
|
||||||
|
that carries untrusted input (HTTP route, CLI argument, queue
|
||||||
|
message, webhook, config file), going one step deeper whenever
|
||||||
|
a hop is a wrapper. Write it as ``entry point -> intermediate
|
||||||
|
call -> package call`` with a ``file:line`` per hop, name what
|
||||||
|
each hop enforces (auth, role check, validation, a flag that
|
||||||
|
is off in production), and say who controls the input. State
|
||||||
|
it plainly when no entry point reaches the sink — that is the
|
||||||
|
most useful result a reader can get.
|
||||||
contextual_cvss_metrics: Optional CVSS v3.1 **environmental**
|
contextual_cvss_metrics: Optional CVSS v3.1 **environmental**
|
||||||
metrics that reframe the published score for this codebase,
|
metrics that reframe the published score for this codebase,
|
||||||
as a mapping of metric to value: ``MAV`` (N/A/L/P), ``MAC``
|
as a mapping of metric to value: ``MAV`` (N/A/L/P), ``MAC``
|
||||||
@@ -1196,15 +1207,12 @@ async def create_dependency_report(
|
|||||||
Set only the metrics your evidence supports (for example
|
Set only the metrics your evidence supports (for example
|
||||||
``{"MAC": "H", "MC": "L"}`` when the vulnerable path needs a
|
``{"MAC": "H", "MC": "L"}`` when the vulnerable path needs a
|
||||||
precondition this deployment enforces and the data at risk is
|
precondition this deployment enforces and the data at risk is
|
||||||
limited). Base the values on a **source-to-sink trace**: start
|
limited). Derive every value from the **source-to-sink
|
||||||
at the entry point that carries untrusted input (HTTP route,
|
trace** you recorded in ``reachability_evidence``: adjust
|
||||||
CLI argument, queue message, webhook, config file), follow
|
``MAV`` / ``MPR`` / ``MUI`` from what the entry point
|
||||||
each hop of the data through this codebase, and end at the
|
actually requires, ``MAC`` from the preconditions the hops
|
||||||
vulnerable package call site. Go one step deeper whenever a
|
enforce, and ``MC`` / ``MI`` / ``MA`` from the data and
|
||||||
hop is a wrapper — never stop at the first caller. Adjust
|
privileges reachable at the sink. You never supply base
|
||||||
``MAV`` / ``MPR`` / ``MUI`` from what that entry point
|
|
||||||
actually requires, and ``MC`` / ``MI`` / ``MA`` from the data
|
|
||||||
and privileges reachable at the sink. You never supply base
|
|
||||||
metrics or a score: the base vector comes from the advisory
|
metrics or a score: the base vector comes from the advisory
|
||||||
and the adjusted score is computed from the resulting vector.
|
and the adjusted score is computed from the resulting vector.
|
||||||
Omit the field when the trace does not change the published
|
Omit the field when the trace does not change the published
|
||||||
|
|||||||
@@ -887,6 +887,7 @@ def test_dep_tool_exposes_contextual_cvss_params() -> None:
|
|||||||
):
|
):
|
||||||
assert field in dep_props
|
assert field in dep_props
|
||||||
assert "source-to-sink" in dep_props["contextual_cvss_metrics"]["description"].lower()
|
assert "source-to-sink" in dep_props["contextual_cvss_metrics"]["description"].lower()
|
||||||
|
assert "source-to-sink" in dep_props["reachability_evidence"]["description"].lower()
|
||||||
assert "file:line" in dep_props["contextual_cvss_reasoning"]["description"].lower()
|
assert "file:line" in dep_props["contextual_cvss_reasoning"]["description"].lower()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user