VEX, CSAF and OpenVEX: Turning SBOM Noise into Exploitability Decisions

VEX, CSAF and OpenVEX: Turning SBOM Noise into Exploitability Decisions

VEX Vulnerability Exploitability: From SBOM Noise to Decisions

A scanner reads your software bill of materials, matches each component against a vulnerability database, and hands you four hundred findings. Perhaps thirty of them can actually be triggered in your product. The other three hundred seventy are real CVEs in real packages, but the vulnerable function is never linked, never called, or sits behind a configuration you do not enable. The scanner cannot tell the difference, because a bill of materials records what is present and says nothing about what is reachable.

VEX vulnerability exploitability statements close that gap. A Vulnerability Exploitability eXchange document is a signed, machine-readable claim by the party who knows the product, stating whether a given CVE affects it and why. It is the missing second half of an SBOM, and in 2026 it is moving from nice-to-have to expected, driven by procurement rules and the EU Cyber Resilience Act.

You will leave this post knowing the four VEX statuses and five justification codes, how CycloneDX, OpenVEX and CSAF differ, and how to wire VEX into CI so triage becomes an automated, auditable pipeline.

What this covers: the triage problem, the VEX data model, the three formats compared, a runnable OpenVEX and scanner workflow, the failure modes that make VEX untrustworthy, and a rollout checklist.

Context and Background

An SBOM answers one question: what is inside this artifact? Formats such as CycloneDX and SPDX list components with identifiers like package URLs (purl), versions and hashes. If you have not yet chosen between them, our guide to CycloneDX versus SPDX for Cyber Resilience Act firmware compliance covers the inventory side. This post starts where that one ends: you have the inventory, and now the findings arrive.

The problem is structural. Vulnerability databases are keyed on package and version ranges, because that is the only thing a database maintainer can know universally. A CVE against a library means “some code path in this library is unsafe.” Whether your product reaches that path depends on your build flags, your linker, your configuration defaults and your threat model. Matching by version therefore over-reports by design. Teams respond with ignore lists, spreadsheets and Slack threads, none of which a customer or auditor can consume.

VEX was formalized by the NTIA software transparency effort and then carried forward by CISA. CISA’s “Minimum Requirements for Vulnerability Exploitability eXchange (VEX)” document states the requirements are format-independent and that CSAF, CycloneDX and OpenVEX can each carry or generate VEX documents. That neutrality is useful: you choose a carrier format, but the semantics (status, justification, product, vulnerability) stay the same.

Three formats matter in practice. CycloneDX embeds a vulnerabilities array with an analysis object, so one BOM can hold both inventory and exploitability. OpenVEX, maintained under the openvex GitHub organization, is a deliberately small JSON-LD format that carries only statements. CSAF, the Common Security Advisory Framework from OASIS, defines a full advisory document with a VEX profile for vendors who already publish advisories. The CISA minimum requirements are available from CISA’s VEX resources, and the OpenVEX specification lives in the openvex/spec repository.

Demand is no longer theoretical. U.S. federal software attestation practice made SBOMs common, and Dependency-Track’s own documentation describes importing supplier-provided CycloneDX VEX and exporting VEX generated from audit decisions. In Europe, the Cyber Resilience Act obliges manufacturers to handle vulnerabilities in the components of products with digital elements and to document that handling. The regulation’s text does not mandate a VEX format by name (I am not aware of one; treat any claim otherwise as unverified), but VEX is the natural machine-readable evidence that you assessed a component vulnerability and reached a decision.

The VEX Reference Model: Four Statuses, Five Justifications

A VEX statement says that, for a named product, a named vulnerability has one of four statuses: not_affected, affected, fixed or under_investigation. A not_affected claim must carry a justification code or an impact statement, and an affected claim should carry an action statement. These rules come from the CISA minimum requirements and are mirrored by OpenVEX.

VEX vulnerability exploitability pipeline from SBOM and scanner to a consumed VEX document

Figure 1: End-to-end VEX flow. The SBOM and a vulnerability feed produce raw findings; a producer triages them into signed VEX statements; consumers filter their scanner output with those statements.

The diagram shows why VEX is a separate artifact rather than an annotation on the scan. The scanner output is ephemeral and tied to a database snapshot. The VEX statement is a durable claim by an accountable author about a product and a CVE, which can be signed, versioned, merged and shipped to customers. The consumer joins the two at scan time, suppressing findings the author has already assessed.

The four statuses

not_affected means no remediation is needed. affected means the product is vulnerable and the author recommends an action, which the CISA document says must be described in an action statement. fixed means the listed product versions contain the fix. under_investigation is an honest placeholder: the author has seen the CVE and has no verdict yet, and the status is expected to change.

The fourth status is more important than it looks. A vendor that silently omits a CVE and a vendor that says under_investigation look identical to a scanner, but they are opposite signals to a customer. Publishing the placeholder starts a clock you can be held to, which is exactly why it builds trust.

The five justification codes

When a statement says not_affected, the machine-readable reason is one of five values, defined in the CISA status justification document and reused verbatim by OpenVEX and by the CSAF flag labels:

Code Meaning Typical evidence
component_not_present The component is not in the product at all SBOM mismatch, such as a test-only dependency
vulnerable_code_not_present Component present, but the affected code was not compiled in Build flags, tree-shaking, stripped modules
vulnerable_code_not_in_execute_path Code present but never executed Call-graph or reachability analysis
vulnerable_code_cannot_be_controlled_by_adversary Code runs, but attacker input cannot reach it Input validation boundary, trust analysis
inline_mitigations_already_exist Built-in protections prevent exploitation Hardening that users cannot disable

The ordering is also a rough ladder of evidence strength. The first two are close to provable from build artifacts. The third needs program analysis. The fourth and fifth require reasoning about attackers, and are the ones most often abused. The CISA text adds a constraint on the last code: the protections must be ones users cannot subvert or disable, and they must fully prevent exploitation by the known vectors.

Product identification decides whether VEX works at all

A statement is only useful if a consumer can map it onto what they run. OpenVEX identifies products by an @id IRI and recommends package URLs, which are valid IRIs. It also supports an identifiers map holding purl, cpe22 or cpe23, a hashes map, and subcomponents for the dependency where the vulnerability originates. CycloneDX uses bom-ref values that point at components inside the same BOM. CSAF uses a product tree with product IDs and relationships.

The pattern that works for containers is a two-level claim: the product is the image digest, and the subcomponent is the vulnerable package purl. That is exactly how the Grype and vexctl example from Chainguard and Anchore expresses a not_affected call for an apk package inside an OCI image.

Decision tree mapping triage evidence to the VEX status and justification for a finding

Figure 2: Triage decision logic. Each question narrows a raw finding to one status, and the answers that stop at not_affected map directly to a justification code.

The tree encodes the order you should ask questions: cheapest and most provable first. Is the component present? Was the vulnerable code compiled in? Can execution reach it? Can an attacker influence the input? Does a mitigation block it? Only after all five fail do you land on affected, and at that point an action statement is mandatory.

Walk-through: Three Formats, One Statement

The same assertion, “CVE-2026-0001 does not affect our gateway image because the vulnerable function is never reached,” can be written in any of the three formats. Seeing them side by side shows what each format optimizes for. The CVE identifier and image names below are placeholders for illustration, not real vulnerabilities.

OpenVEX: the minimal carrier

An OpenVEX document (specification v0.2.0 at the time of writing) requires @context, @id, author, timestamp, version and statements. Each statement requires a vulnerability and a status, plus a product and a timestamp that may be inherited from the document. A not_affected statement needs a justification, an impact_statement, or both; the spec recommends the machine-readable justification and discourages automation from depending on free text.

{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "@id": "https://example.com/vex/gateway-fw-2026-001",
  "author": "Example Corp Product Security",
  "role": "Document Creator",
  "timestamp": "2026-10-09T08:00:00+05:30",
  "version": 1,
  "statements": [
    {
      "vulnerability": { "name": "CVE-2026-0001" },
      "products": [
        {
          "@id": "pkg:oci/gateway-fw@sha256%3A1111111111111111111111111111111111111111111111111111111111111111",
          "subcomponents": [
            { "@id": "pkg:deb/debian/libexample@2.4.1-1" }
          ]
        }
      ],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path",
      "impact_statement": "parse_legacy() is linked but no code path in gateway-fw calls it."
    }
  ]
}

Two details matter. First, the version field must increase whenever anything in the document changes, including statements; consumers rely on that for ordering. Second, a statement’s own timestamp overrides the document timestamp, and when you update a document existing statements should keep their original timestamps so earlier claims remain verifiable.

CycloneDX VEX: inventory and exploitability in one BOM

CycloneDX 1.6 places exploitability in vulnerabilities[].analysis. I verified the enumerations against the published 1.6 JSON schema. The state field takes resolved, resolved_with_pedigree, exploitable, in_triage, false_positive or not_affected. The justification field takes code_not_present, code_not_reachable, requires_configuration, requires_dependency, requires_environment, protected_by_compiler, protected_at_runtime, protected_at_perimeter or protected_by_mitigating_control. The response field is an array drawn from can_not_fix, will_not_fix, update, rollback and workaround_available.

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "version": 1,
  "vulnerabilities": [
    {
      "id": "CVE-2026-0001",
      "source": { "name": "NVD", "url": "https://nvd.nist.gov/" },
      "analysis": {
        "state": "not_affected",
        "justification": "code_not_reachable",
        "detail": "parse_legacy() is linked but never called by gateway-fw."
      },
      "affects": [ { "ref": "pkg:deb/debian/libexample@2.4.1-1" } ]
    }
  ]
}

Note the vocabulary difference. CycloneDX has nine justification values against CISA’s five, and they are finer on the mitigation side: it distinguishes protection by compiler, at runtime, at perimeter or by a mitigating control. It also mixes lifecycle state (resolved) with exploitability (not_affected) in one field, where OpenVEX separates fixed from not_affected by status alone. Mapping between the two is possible but lossy, so pick one as your source of truth and generate the other.

CSAF: the advisory-grade profile

CSAF 2.0 became an OASIS Standard on 18 November 2022. Its VEX profile requires $.document.category to be csaf_vex, and per-vulnerability product_status groups use the names known_affected, known_not_affected, fixed and under_investigation. For known_not_affected products, the spec requires an impact statement, either as a machine-readable flag in $.vulnerabilities[*].flags or as human-readable justification in threats. The flag labels line up with the CISA justification codes.

CSAF is heavier because it was designed for vendors who publish advisories at scale: a product tree, document tracking with revision history, distribution markings such as TLP, and a discovery model through provider metadata. If you already run an advisory process, the VEX profile slots into it. If you do not, you are adopting more than you need.

A status note on versions, since this changes quickly: as of the date of this post, the OASIS CSAF 2.1 document I retrieved is a Committee Specification Draft 03 dated 11 September 2026, not a finished OASIS Standard. CSAF 2.0 remains the approved standard. Treat any 2.1-specific field as subject to change until it is approved.

Comparison flow showing CycloneDX VEX, OpenVEX and CSAF as carriers of the same exploitability statement

Figure 3: One statement, three carriers. All converge on the same triage output that scanners consume, but differ in how much surrounding structure they require.

Choosing a carrier

Need Best fit Why
Ship VEX with a CycloneDX SBOM you already generate CycloneDX VEX One artifact, bom-ref links to components
Lightweight statements for containers and CI OpenVEX Tiny schema, purl-first, vexctl tooling
Public advisories with revision history CSAF VEX profile Product tree, tracking, provider discovery
Regulated or large-vendor audience CSAF, with an OpenVEX or CycloneDX export Auditors recognize advisory structure
Dependency-Track ingestion CycloneDX VEX Native import and export

My own recommendation, offered as opinion: authoring in OpenVEX and projecting to the other formats is the cheapest path for small teams, because the document is small enough to review in a pull request. Larger vendors with an existing PSIRT process will usually end up in CSAF regardless.

Wiring VEX Into Triage Automation

The value of VEX is realized only if it changes what a scanner reports. The three tools most teams touch are vexctl for authoring, Grype or Trivy for consuming, and Dependency-Track for portfolio-level tracking.

Authoring with vexctl

The vexctl tool from the OpenVEX project documents four commands: create, merge, attest and filter. Chainguard and Anchore’s announcement of Grype’s OpenVEX support shows the pattern with a not_affected statement:

vexctl create \
  --vuln=CVE-2026-0001 \
  --product='pkg:oci/gateway-fw@sha256%3A1111111111111111111111111111111111111111111111111111111111111111' \
  --subcomponents='pkg:deb/debian/libexample@2.4.1-1' \
  --status=not_affected \
  --justification=vulnerable_code_not_in_execute_path \
  --impact-statement="parse_legacy is never called" \
  > gateway.openvex.json

The merge command combines statements for a product from several documents, which is how you layer your own assessments over upstream ones. The attest command wraps VEX in a signed attestation that can be attached to a container image, and filter strips VEX-resolved entries from scanner results such as SARIF. Flag details evolve, so run vexctl --help against your installed version rather than trusting a snippet.

Consuming with Grype and Trivy

Grype accepts OpenVEX through --vex. In the Chainguard and Anchore walkthrough, a baseline scan reported one medium-severity match, adding the VEX file reduced it to zero matches and one ignored, and the suppressed finding remained visible in the JSON output’s ignored list. That last property is the one auditors care about: suppression is recorded rather than erased.

Trivy supports VEX through --vex as well. Its documentation for the 0.5x series labels the feature experimental and warns it may change without backward compatibility, and says OpenVEX and CSAF work with all targets while CycloneDX VEX works only in the independent BOM-plus-VEX arrangement against a CycloneDX SBOM input. Check the current Trivy documentation for the status in your version, since experimental labels get removed over time.

# Scan an image, suppressing findings already assessed
grype registry.example.com/gateway-fw@sha256:1111... \
  --vex gateway.openvex.json -o json > findings.json

trivy image registry.example.com/gateway-fw:2.4.0 \
  --vex gateway.openvex.json --exit-code 1 --severity HIGH,CRITICAL

A CI gate that respects VEX

The shape of a good pipeline is: generate the SBOM at build time, scan it, apply the repository’s VEX files, and fail only on what remains. The VEX files live in the same repository as the code, so a change to a not_affected claim goes through code review.

name: vuln-gate
on: [pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t gateway-fw:ci .
      - name: Scan with VEX applied
        run: |
          grype gateway-fw:ci \
            $(for f in vex/*.openvex.json; do printf -- '--vex %s ' "$f"; done) \
            --fail-on high
      - name: Validate VEX freshness
        run: python3 tools/check_vex.py vex/

The check_vex.py step is yours to write, and it is where the real discipline lives. It should reject statements missing a justification, statements whose timestamp is older than your review window, and not_affected claims whose referenced component version no longer appears in the SBOM. I have not seen a standard tool that does all three, so treat this as a small piece of in-house glue.

Sequence of CI build, scan, VEX filter and publish steps for VEX triage automation

Figure 4: A triage automation loop. Scans produce findings, engineers write VEX statements through pull requests, and the published VEX feeds the next scan and the customer-facing feed.

Portfolio view with Dependency-Track

Dependency-Track ingests CycloneDX SBOMs and tracks components across projects. Its documentation says it supports CycloneDX VEX, lets consumers upload supplier VEX, and generates VEX dynamically from audit decisions on each application, with an API-first design so updated VEX can be produced when decisions change. For an organization with dozens of products, this turns a VEX file into the output of an audit workflow rather than a hand-edited artifact. I did not verify the full list of analysis states in the version you may run, so check its Analysis States page.

Producing Evidence You Can Defend

A VEX statement is a liability if the evidence behind it is thin. The justification codes are claims about code and attackers, and each needs a repeatable way to be established. This section covers where the evidence comes from and how to record it.

Build-time evidence: the cheap wins

The strongest and cheapest statements come from facts about the build. If a CVE affects a module that your build flags exclude, vulnerable_code_not_present is provable by inspecting the produced binary or by showing the symbol is absent. If a dependency is only used in tests and never ships, component_not_present follows from comparing the shipped artifact’s SBOM with the repository’s lockfile. This is why the quality of the SBOM matters: an SBOM generated from the final image reflects what is present, while one generated from a lockfile reflects what you intended. Where the two disagree, trust the artifact.

For embedded and IoT firmware, build-time evidence is often the main source. Static linking with section garbage collection, disabled kernel config options and absent daemons all leave verifiable traces. A CVE in a protocol stack you configured out at compile time is a clean vulnerable_code_not_present claim, and the build log or a symbol table dump is the supporting artifact.

Reachability analysis: stronger, costlier, and probabilistic

vulnerable_code_not_in_execute_path is the claim most teams want and the one most often weakly supported. Reachability analysis builds a call graph from your entry points and asks whether any path touches the vulnerable function. Static call graphs over-approximate in languages with reflection, dynamic dispatch or plugin loading, which makes a “no path” result reliable but a “path exists” result uncertain. Dynamic analysis, such as coverage collected during integration tests, under-approximates: an unexercised path is not proof of unreachability.

The honest framing is to record how you reached the conclusion. A statement supported by a static call graph from all public entry points is a different strength of claim than one based on test coverage. OpenVEX offers a free-text impact_statement, and CycloneDX offers detail; use them to name the method and tool version, even though the spec discourages automation from parsing them. A reviewer can then challenge the method, not just the verdict.

Attacker-control and mitigation claims

The fourth and fifth codes require a threat argument. vulnerable_code_cannot_be_controlled_by_adversary says the code runs but attacker data cannot influence the vulnerable parameters. That is a claim about trust boundaries, and it can be invalidated by a later architectural change, such as exposing an internal API to a partner. inline_mitigations_already_exist has the strictest wording in the CISA text: the protections cannot be subverted or disabled by users and fully prevent exploitation by known vectors. A WAF rule that an operator can switch off does not qualify. Reserve these two codes for statements backed by a written design note.

A worked triage budget

Consider a hypothetical gateway image with a scan of 400 findings. These numbers are illustrative, not measurements. Suppose component presence checks remove 60 findings in test-only layers. Build-flag analysis removes another 90 where the vulnerable module was never compiled. Reachability analysis on the remaining 250 clears 110 more. Of the final 140, a threat review dismisses 25, leaving 115 that are real, of which perhaps 20 are high priority.

The arithmetic matters because it shows where the effort goes. The first two filters are nearly free once automated and remove more than a third of the noise. The reachability step is expensive per finding but clears a large block. The threat review is human-time-heavy and clears the least. A team with a fixed engineering budget should automate the first filters, buy or build reachability for its main language, and spend people only on the residue. Sequencing the work in that order, rather than starting with manual review, is the main efficiency lever.

Handling the long tail: inherited and merged statements

Most of your dependencies come from upstream distributions, and those upstreams may already publish VEX. Chainguard publishes OpenVEX for its images, and several Linux vendors publish CSAF VEX for their packages. You can merge upstream statements with your own, but you must settle precedence. A sensible rule is that your product-specific statements override upstream package-level statements, because you know your configuration, while upstream fixed statements establish when a package version is safe. In OpenVEX, a statement’s product data overrides document-level product data and its own timestamp overrides the document’s, which gives you a deterministic way to resolve overlaps when you design your merge step.

Trade-offs, Gotchas, and What Goes Wrong

VEX shifts trust from a tool to a person or organization. That is the point, and also the risk.

Stale claims. A not_affected statement is true for a specific build. When a dependency updates or a feature flag changes, the claim can silently become false. Consumers apply the statement by product and vulnerability identifier, so the stale claim keeps suppressing a real finding. Mitigate by tying statements to image digests or exact versions rather than floating tags, and by expiring claims on a schedule.

Over-trusting suppression. Suppressing a finding because a supplier says it is not affected means you inherit their analysis error. Dependency-Track’s design allows consumers to share their own auto-generated VEX with suppliers when they find discrepancies, which is a healthy feedback path, but most consumers will not audit. Treat third-party VEX as a prior, not a verdict, for your highest-severity findings.

Identifier mismatch. A VEX statement keyed to a purl will not match a scanner that identifies the package by CPE, or a purl with different qualifiers such as architecture or distro. This causes the opposite failure: the statement exists but suppresses nothing. Test your pipeline with a known statement and confirm the finding moves to the ignored list before relying on it.

Format drift. Trivy labels its VEX support experimental in the documentation I read, and CSAF 2.1 is still a draft. Anything you build against a moving target needs a small compatibility test in CI so a scanner upgrade does not quietly reintroduce hundreds of findings or, worse, change what is suppressed.

Mixing exploitability with severity. VEX says whether you are affected, not how bad it is. A CVSS score and a VEX status answer different questions. Pair VEX with a likelihood signal such as EPSS or a known-exploited list for prioritization of what remains; do not use VEX as a substitute for risk scoring.

Gaming and compliance theater. Because not_affected makes a dashboard green, there is pressure to use it liberally. A policy that counts closed findings as success rewards exactly that behavior. Measure instead the proportion of not_affected claims that were later overturned, and require a second reviewer for the two threat-based justification codes.

Regulatory ambiguity. For the Cyber Resilience Act, I could not confirm that any harmonised standard names a specific VEX format, so do not assume one carrier satisfies the regulation. Document your handling process, keep the evidence, and be prepared to translate formats.

Practical Recommendations

Start with scope, not format. Pick one product line, generate its SBOM from the final artifact, and run a scanner to establish the baseline count. That number is your before picture.

Next, automate the cheap filters. Component presence and build-flag checks need no new tooling beyond comparing SBOMs and build configs, and they remove the largest bulk of noise. Then choose a carrier. If you already produce CycloneDX, use CycloneDX VEX. If you ship containers and want small reviewable files, author OpenVEX. If you publish advisories, add the CSAF VEX profile.

Keep VEX in version control beside the code, review it like code, sign it when it leaves the building, and publish it where customers can discover it. Treat under_investigation as a first-class status with a service-level target for resolving it. Finally, schedule re-evaluation: every dependency bump should trigger a check that the claims referencing the old version are re-confirmed or retired.

A short rollout checklist:

  • Generate the SBOM from the built artifact, not the lockfile.
  • Record a baseline scan count before applying any VEX.
  • Automate presence and build-flag filters first.
  • Require a justification code on every not_affected statement.
  • Key statements to digests or exact versions and a purl the scanner understands.
  • Apply VEX in CI and confirm suppressed findings appear in the ignored list.
  • Add a freshness check that expires or flags old statements.
  • Track the overturn rate of not_affected claims as a quality metric.
  • Sign and publish VEX alongside releases.

Frequently Asked Questions

What is VEX and how is it different from an SBOM?

An SBOM lists the components inside a software artifact. A VEX document makes statements about specific vulnerabilities for a named product, saying whether it is not_affected, affected, fixed or under_investigation. The SBOM tells a scanner what to look up; the VEX tells the consumer which of the resulting matches are actually exploitable in that product. They are complementary, and CycloneDX can carry both in a single document.

Which VEX format should I use: CycloneDX, OpenVEX or CSAF?

CISA’s minimum requirements are format-independent, so the choice is practical. Use CycloneDX VEX if you already ship CycloneDX SBOMs or use Dependency-Track. Use OpenVEX for small, purl-based statements in container and CI workflows. Use the CSAF VEX profile if you publish security advisories and need a product tree, revision history and provider discovery. Many teams author in one and export to another.

What are the VEX status values and justification codes?

The four statuses are not_affected, affected, fixed and under_investigation. A not_affected statement needs a justification, drawn from component_not_present, vulnerable_code_not_present, vulnerable_code_not_in_execute_path, vulnerable_code_cannot_be_controlled_by_adversary and inline_mitigations_already_exist, or an impact statement. An affected statement should include an action statement describing remediation or mitigation. CycloneDX uses its own state and justification vocabularies.

Do Grype and Trivy support VEX?

Yes. Grype accepts OpenVEX documents through the --vex flag and moves matched findings to its ignored list. Trivy also supports --vex; its documentation labelled the feature experimental in the version I read, with OpenVEX and CSAF working across targets. Because support and flags evolve, confirm behavior against your installed version and add a regression test that a known statement suppresses a known finding.

Does the EU Cyber Resilience Act require VEX?

I could not verify that the Cyber Resilience Act or a harmonised standard mandates VEX or a specific format. The regulation does require manufacturers to handle vulnerabilities, including those in third-party components, and to keep documentation. A VEX document is a practical, machine-readable way to evidence that handling, but treat it as supporting evidence and check current guidance from your notified body or legal counsel.

Can a VEX statement be wrong or outdated?

Yes. A VEX statement is a claim by its author about a specific product build, and it can go stale when dependencies, flags or architecture change. Bind statements to exact digests or versions, expire them on a schedule, record how the evidence was gathered, and review the two threat-based justification codes with a second person. Track how often not_affected claims are later overturned as a quality signal.

Further Reading

By Riju — about

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *