Supply chain compromise vs CVE: why `risk_state: none` does not mean safe

A package can contain no known vulnerability and still be actively malicious.
That distinction sounds obvious when stated plainly, but a large part of software security infrastructure is still organised around a different question:
Does this version have a CVE?
A CVE describes a vulnerability in software.
A supply chain compromise describes software that an attacker has deliberately poisoned.
Those are different conditions. They require different signals.
A package can therefore return:
{
"risk_state": "none",
"supply_chain": {
"compromised": true
}
}
There is no contradiction in that response.
risk_state: "none" says that the version has no CVE-derived vulnerability state.
supply_chain.compromised: true says that the version itself is a known malicious publish.
Attestd deliberately keeps those signals independent because collapsing them into a single safety score loses information that an automated system needs to make the correct decision.
A vulnerability is not the same thing as malicious code#
Most vulnerabilities begin as mistakes.
A maintainer ships an authentication bypass, memory-safety error, injection flaw, or other defect. Someone discovers it. A CVE is assigned. Vulnerability databases describe the affected versions. A patched release may follow.
The software was not intended to attack you. It contains a weakness that an attacker may be able to exploit.
A supply chain compromise reverses the model.
An attacker gains the ability to publish a package, hijacks a maintainer account, steals a registry token, poisons a dependency, or otherwise introduces code whose purpose is to compromise the machine that consumes it.
There may be no vulnerability to enumerate because exploitation of a programming mistake is not required.
The package itself is the payload.
That is why checking only CVEs cannot answer the broader question developers actually care about:
Should this software be allowed to run?
NVD is designed to describe vulnerabilities. It is not a registry of every malicious package version published to npm or PyPI. Attestd vs NVD reflects exactly that boundary: vulnerability intelligence and supply chain integrity describe different conditions.
A real example: LiteLLM 1.82.7#
LiteLLM 1.82.7 is a confirmed malicious PyPI publish associated with the TeamPCP supply chain attack.
There is no CVE attached to the version.
Attestd currently uses it as the compromised reference package in its supply chain documentation.
The request is straightforward:
curl "https://api.attestd.io/v1/check?product=litellm&version=1.82.7" \
-H "Authorization: Bearer $ATTESTD_API_KEY"
The documented production response is:
{
"product": "litellm",
"version": "1.82.7",
"supported": true,
"risk_state": "none",
"risk_factors": [],
"actively_exploited": false,
"remote_exploitable": false,
"authentication_required": false,
"patch_available": false,
"fixed_version": null,
"confidence": 1,
"cve_ids": [],
"cves": null,
"max_epss": null,
"supply_chain": {
"compromised": true,
"sources": [
"osv",
"registry"
],
"malware_type": "backdoor",
"description": "TeamPCP supply chain attack: a malicious version contained a credential stealer in proxy_server.py targeting LLM provider API keys. Published at 10:39 UTC and removed within six hours after community detection.",
"advisory_url": "https://docs.litellm.ai/blog/security-update-march-2026",
"compromised_at": "2026-03-24T10:39:00Z",
"removed_at": "2026-03-24T16:00:00Z",
"provenance": null
},
"supply_chain_monitored": true,
"typosquat": null,
"last_updated": "2026-04-27T16:07:47.644177Z"
}
The important fields are:
risk_state: none
cve_ids: []
supply_chain.compromised: true
A branch that evaluates only risk_state sees no CVE-derived risk.
A branch that evaluates supply chain state sees a known malicious package.
Those are radically different outcomes from the same API response.
Compare it with a clean monitored package#
Now compare LiteLLM with a package that is monitored for supply chain compromise and currently has neither a CVE-derived risk state nor a known malicious publish.
Attestd's current documentation uses LangChain 0.3.0 as the clean example:
{
"product": "langchain",
"version": "0.3.0",
"supported": true,
"risk_state": "none",
"risk_factors": [],
"actively_exploited": false,
"remote_exploitable": false,
"authentication_required": false,
"patch_available": false,
"fixed_version": null,
"confidence": 0.9,
"cve_ids": [],
"cves": null,
"max_epss": null,
"typosquat": null,
"supply_chain": {
"compromised": false,
"sources": [],
"malware_type": null,
"advisory_url": null,
"compromised_at": null,
"removed_at": null,
"provenance": null
},
"supply_chain_monitored": true,
"last_updated": "2026-02-23T18:21:30Z"
}
Both responses contain:
risk_state: none
Only one contains:
supply_chain.compromised: true
Only one should be blocked.
That comparison is why risk_state cannot be treated as a universal software-safety verdict.
It answers one class of question.
Supply chain integrity answers another.
The failure is often in the branch logic#
The dangerous implementation is not necessarily a bad vulnerability scanner.
It can simply be bad decision logic built on top of a good vulnerability signal.
For example:
if result.risk_state == "none":
deploy()
That code silently assumes:
no known CVE risk = safe software
That implication does not hold.
The conditions need to be evaluated independently:
if result.supply_chain and result.supply_chain.compromised:
block()
if result.risk_state in ("critical", "high"):
block()
The same principle applies before installing a dependency, approving an automated upgrade, exposing a service, or allowing an autonomous agent to execute software.
In a supply chain-aware CI/CD workflow, supply_chain.compromised can be treated as an immediate fail condition independently of risk_state.
This is an important architectural distinction.
A security API should not force the consumer to infer that one type of clean result implies another type of clean result.
CVEs and compromises also have different remediation models#
The distinction matters after detection too.
When a vulnerable package has a known fixed version, the correct response may be straightforward:
affected: 4.2.0
fixed: 4.2.1
Upgrade and continue.
A malicious publish can require a very different response.
If the package executed during installation, build, import, or testing, the machine may already have been exposed to hostile code.
That can mean investigating:
- registry credentials
- GitHub tokens
- cloud credentials
- environment variables
- API keys
- signing material
- source-code access
- persistence mechanisms
Simply upgrading away from the malicious version does not necessarily undo what happened while it was present.
This is another reason malicious-publish state should not be compressed into vulnerability severity.
The underlying security event is different.
There is a third independent condition too#
CVE risk and malicious-publish status still do not cover every software-integrity failure.
Sometimes the package name itself is the problem.
A developer mistypes a dependency.
An attacker registers a convincing typosquat.
An AI coding assistant hallucinates a package that sounds plausible but does not correspond to the intended library.
That is why Attestd exposes three independent signals:
risk_state
supply_chain.compromised
typosquat
They are not three ways of expressing one score.
They answer three separate questions:
- Does this version have known vulnerability risk?
- Is this version a known malicious publish?
- Is the requested package name itself suspicious or incorrect?
This becomes especially important when the consumer is an autonomous system.
A human developer can see an unfamiliar package and decide to investigate.
An agent installing dependencies needs a machine-readable condition before the action occurs.
Attestd for Developers applies that model at the point where a coding assistant is about to install or recommend a dependency.
The problem gets larger as software becomes more autonomous#
Traditional vulnerability management assumes a human exists somewhere in the decision path.
A scanner produces an advisory.
A developer or security engineer reads it.
Someone decides what to do.
Autonomous software changes that model.
A coding agent can select a package.
An infrastructure agent can upgrade a component.
A CI pipeline can deploy an image.
A remediation system can execute a change.
The security signal increasingly needs to arrive before the action in a form software can branch on directly.
That makes semantic precision more important, not less.
Consider these two states:
{
"risk_state": "none",
"supply_chain": {
"compromised": false
}
}
and:
{
"risk_state": "none",
"supply_chain": {
"compromised": true
}
}
To a vulnerability-only system, they may look equivalent.
To the system deciding whether to execute the software, they are opposites.
This is part of the broader argument behind Attestd's Autonomous Infrastructure Thesis: when software makes the decision itself, the security layer needs to return deterministic conditions rather than another document for a human to interpret.
Check the condition you actually care about#
CVE scanning remains necessary.
If a package contains a remotely exploitable vulnerability, you need to know.
If exploitation has been confirmed in the wild, you need to know that too.
But the absence of a CVE is not evidence that a dependency is trustworthy.
Supply chain compromise is a different failure mode with a different signal and a different response condition.
Package-name integrity is another.
The safe automation rule is therefore not:
risk_state == none
→ proceed
It is:
known CVE risk?
known supply chain compromise?
package name integrity problem?
Then branch on each answer independently.
That is the difference between asking whether software has a known vulnerability and asking whether the software should be allowed to act.
Responses above are the current reference responses published in the Attestd supply chain documentation as of August 29, 2026.
Related
EditorialHow to audit your npm dependencies in 30 minutes
A practical 30-minute npm dependency audit covering CVE scanning, lockfile inspection, supply chain compromise checking, typosquat detection, and CI
Robert7 min read
EditorialWhy CVSS scores mislead autonomous systems
CVSS measures theoretical severity. Only 2.3% of CVSS 7+ vulnerabilities get exploited. 28% of exploited CVEs score medium. Here is what systems need instead.
Robert8 min read
EditorialWhat every developer should know about dependency security
CVE scanners miss supply chain attacks. Lockfiles are not guarantees. AI tools introduce new vectors. Here is what dependency security requires in 2026.
Robert6 min read