AI Pentesting, Part 6: Web CVE Bot: From Advisory Text to a Patch Decision

A CVE summariser becomes useful when it can explain why a particular asset is affected, what evidence is missing, and how the owner can verify a fix. It becomes dangerous when an invented version range or a banner match automatically launches an exploit. Build a triage system, not an unattended exploitation bot.

Lab boundary: written authorisation, synthetic identities and data, isolated targets, bounded requests, and human approval for active actions. Examples are instructional fixtures, not claims of testing a live organisation. Tool inventory reviewed 2026-10-28; compatibility and availability can change.

Evidence and trust boundariesAdvisory + SBOMIdentity matchingApplicability gatePatch + retestPropose. Enforce. Verify.
A CVE identifier is an advisory key. Applicability, exposure, and remediation require asset-specific evidence.

1. Separate collection, interpretation, and action

Web CVE Bot here describes a reference architecture, not a verified product with that name. Its collectors ingest vendor advisories, CVE records, enrichment feeds, and an approved asset inventory. A deterministic layer resolves identifiers and versions. An LLM explains the supplied evidence and drafts owner questions. A separate approval service opens a patch task or schedules a non-destructive lab check.

Retain the original advisory, retrieval timestamp, content hash, and revision history. CVE records can be reserved, rejected, disputed, or updated. NVD enrichment can lag vendor disclosure. Treat a scanner's product guess and an HTTP Server header as weak observations, not authoritative package inventory. Do not fetch or execute public proof-of-concept code automatically.

{
  "advisory_key": "LAB-ADV-001",
  "source_type": "synthetic_vendor_fixture",
  "component": "example-web",
  "affected_range": ">=2.4.0 <2.4.3",
  "fixed_version": "2.4.3",
  "prerequisites": ["optional preview feature enabled"],
  "exploit_execution_allowed": false,
  "status": "needs_inventory_confirmation"
}

This synthetic advisory deliberately has no real CVE number. It lets us test parsing and decision logic without inventing claims about an actual vulnerability.

2. Resolve products and versions correctly

Use package URLs (purl) for ecosystem identity, CPE where appropriate for product matching, and vendor-specific identifiers when neither captures a deployment. Include direct and transitive dependencies, container image digest, operating-system package release, and build provenance. A front-end banner may describe a reverse proxy rather than the vulnerable application.

Never compare versions lexicographically: 2.10.0 must not sort before 2.9.0. Use the package ecosystem's version implementation. Debian revisions, RPM epochs, Java qualifiers, Python pre-releases, and vendor hotfixes do not share one universal ordering. Backported fixes can leave the upstream version unchanged; verify the distribution advisory and package release before demanding a major upgrade.

EvidenceWhat it supportsWhat remains unknown
SBOM lists componentComponent present in a specific buildRuntime exposure and feature enablement
Banner matches productPossible externally visible technologyActual package identity and patch level
Vendor fixed releaseDocumented remediation targetWhether that release was deployed everywhere
VEX not_affected statementIssuer's stated applicability analysisTrust, scope, justification, and current validity

3. Use severity, exploitation, and exposure separately

CVSS describes severity under a scoring model. EPSS estimates the probability of observed exploitation in a defined forward-looking window; it is not asset-specific impact. CISA KEV identifies vulnerabilities known to be exploited according to its inclusion criteria. Absence from KEV is not evidence that exploitation is impossible. A public exploit reference is also not proof of exploitation in your environment.

Combine those signals with internet exposure, authentication prerequisites, asset criticality, compensating controls, and patch feasibility. Keep the inputs visible rather than compressing everything into an unexplained AI risk score. An internal unauthenticated service handling signing keys may outrank an internet-facing low-impact component. An isolated lab VM should not receive the same urgency as a production identity provider.

Decision fields:
component_match: confirmed | possible | no_match
version_applicability: affected | fixed | unknown
feature_prerequisite: met | absent | unknown
exposure: internet | internal | isolated | unknown
known_exploitation: source-backed | not_listed | unknown
business_owner: required
next_action: owner_confirmation | patch | mitigation | monitor
Every factual field requires evidence_ids.

Unknown must remain a valid state. Do not let a missing inventory field silently become 'not affected'.

4. Build and test a bounded triage loop

  1. Import an approved inventory snapshot and record its age.
  2. Deduplicate advisories by canonical identifier while retaining revisions.
  3. Resolve candidate component matches and ecosystem-native versions.
  4. Ask the model to summarise prerequisites using supplied passages only.
  5. Require an owner to confirm deployment and feature state.
  6. Create a patch or mitigation task with evidence and retest criteria.
  7. Re-evaluate when the advisory, inventory, or exposure changes.

Test fixtures should cover an affected component, a fixed release, a backported fix, a disabled vulnerable feature, a rejected advisory, and an unknown build. A seventh fixture should contain an advisory paragraph instructing the assistant to upload inventory elsewhere. Confirm that it is stored as data and cannot change destinations or policy.

Use retrieval filters to keep product families and advisory revisions separate. RAG improves evidence access, but similarity search can return a similarly named product or an obsolete fix. Validate exact identity and revision before summarisation.

5. Three applicability examples

Container mismatch: an SBOM says a vulnerable library is present in image digest A, but production runs digest B. Verify the deployment digest before opening a finding. Do not close the issue merely because the latest image is patched if old replicas still serve traffic.

Feature prerequisite: the synthetic advisory affects a preview parser enabled by configuration. Version matching yields 'candidate affected'; configuration evidence determines whether the vulnerable code path is active. Disabled configuration may be a temporary mitigation, not a reason to ignore a vendor patch.

Backport: a distribution ships an upstream-looking version with a security revision. Use the distribution's advisory mapping and installed package release, not an LLM's memory of upstream version numbers. A VEX statement can document reasoning but must identify its issuer, exact product, status, justification, and validity.

For all three, ask the assistant to produce the strongest competing explanation and the one cheapest owner check that distinguishes it. This is more useful than generating an exploit narrative.

6. Verify remediation without weaponising the advisory

After patching, collect installed package evidence, image digest, rollout status, and a vendor-recommended non-destructive verification. Confirm that canary, background-worker, and disaster-recovery instances are covered. A changed banner is not enough. Keep regression tests for the root cause where source and a lab reproduction are available.

Task: explain applicability from these supplied evidence records.
Do not invent CVE details, version ranges, or exploit outcomes.
Return affected assets, unresolved assets, evidence IDs,
       vendor remediation, temporary controls, retest criteria.
If the source does not establish a fact, write unknown.
Do not retrieve or execute proof-of-concept code.

Measure component-match precision, unresolved inventory age, time to owner confirmation, patch completion, and reopened false closures. Keep a human-readable explanation alongside structured fields. Part 7 consumes the approved manifest and shows how to scale scanners without turning uncertainty into uncontrolled traffic.

7. Step-by-Step Lab: Triage a Synthetic Advisory Against Inventory

Prerequisites: An offline runtime, a synthetic vendor advisory, and an inventory snapshot with explicit build and feature state. No live CVE feed, public exploit, or real vendor claim is needed. The narrow version logic below handles only its labelled numeric fixture; use ecosystem-native version comparison for real packages.

  1. Create advisory LAB-ADV-021 for example-web: version 2.4.0 through 2.4.2 is affected only when the preview parser is enabled; 2.4.3 is fixed. Mark every field synthetic and retain the original record.
  2. Create three assets: one affected build with the feature enabled, one fixed build, and one affected-looking build with unknown feature state. Give each a stable asset ID, owner, and inventory timestamp.
  3. Run the offline classifier. It should retain unknown as a first-class decision rather than interpreting missing configuration as not affected.
  4. Ask AI to explain each result using only the supplied advisory and inventory. Require the exact evidence IDs and one owner question for every unresolved asset.
  5. Add a distribution-backport fixture described by an explicit vendor package-release statement. Do not feed it into the toy numeric matcher; route it to the ecosystem/vendor-specific applicability path.
  6. Write a patch task for the confirmed candidate with the owner, exact deployment identity, remediation target, temporary controls, and a non-destructive retest.
  7. Change the synthetic inventory to the fixed build and rerun. Keep the prior result and revision history, and verify that no replica or background worker remains on the earlier digest.
function applicability(asset) {
    if (asset.product !== "example-web") return "no_match";
    const [major, minor, patch] = asset.version;
    if (![major, minor, patch].every(Number.isInteger)) return "unknown_version";
    if (major !== 2 || minor !== 4) return "outside_fixture_range";
    if (patch >= 3) return "fixed";
    if (patch < 0 || asset.preview === undefined) return "needs_feature_confirmation";
    return asset.preview ? "affected" : "feature_disabled_mitigation";
}
const assets = [
    { product: "example-web", version: [2, 4, 2], preview: true },
    { product: "example-web", version: [2, 4, 3], preview: true },
    { product: "example-web", version: [2, 4, 2] }
];
const decisions = assets.map(applicability);
if (decisions.join("|") !== "affected|fixed|needs_feature_confirmation") throw Error("applicability mismatch");
console.log(JSON.stringify(decisions));

Expected result: The decisions are affected, fixed, and needs_feature_confirmation. No exploit is executed. A disabled feature is recorded as a mitigation requiring review, not proof that the vendor patch is unnecessary. The fixture intentionally does not implement SemVer ranges, epochs, qualifiers, backports, or vendor release ordering.

8. Worked Examples and Expected Outcomes

Example A: a stale container inventory

The vulnerable SBOM belongs to an old image while the running deployment uses a newer digest. Verify all running workloads and image digests before asserting applicability. Do not close the ticket merely because a new image exists in the registry.

Example B: a high score with low exposure

An advisory has high generic severity but the reviewed component runs in an isolated lab. Preserve severity and exposure separately. A risk owner may still choose urgent patching; the assistant must not turn a generic score into an invented internet-facing attack path.

Example C: a source revision changes the answer

A vendor updates a prerequisite after initial disclosure. Keep both versions, invalidate cached summaries bound to the old source hash, and reopen affected applicability decisions. This is a reason for evidence revisioning, not a reason to trust the latest model answer without a source.

{"advisory":"LAB-ADV-021","asset":"lab-web-01","match":"confirmed","feature":"enabled","next_action":"owner-approved patch","evidence_ids":["advisory-r1","inventory-r3"],"exploit_run":false}

9. Troubleshooting, Retesting, and Completion Evidence

SymptomLikely causeDiscriminating check
Version order looks wrongLexicographic or wrong-ecosystem comparisonUse the ecosystem's tested version library and vendor package release
Missing feature state becomes cleanUnknown was collapsed into falseRequire an explicit unknown state and owner confirmation
Patched finding returnsOld replicas, stale inventory, or revised advisoryCompare deployment digests, timestamps, and advisory revisions

Retest and completion: Retain advisory originals, normalised identity, inventory version, owner confirmation, patch decision, and rollout evidence. Test rejected advisories, product-name collisions, absent inventory, backports, and a fixed-build positive control. Every unresolved asset should remain visible until evidence closes the question.

10. Real Tool Workflow: Generate an SBOM with Syft and Review Matches with Grype

Prerequisites: Reviewed Syft and Grype releases, an owned local source/build directory, access to the approved vulnerability database workflow, and the exact running build identity. Tool installation must follow your software process; no curl-to-shell installer or dependency installation is needed for reading this guide.

Use reviewed releases and record the versions actually installed. Command references for this workflow were reviewed on 29 October 2026; product support and flags can change. Instructions and output shapes are not claims of a live assessment.

ToolRoleImportant boundary
SyftInventory packages in a local directory and export an SBOMPresence and completeness depend on the target and cataloguers
GrypeMatch an SBOM against known vulnerability recordsA match is a triage candidate, not an exploit or proof of runtime reachability
PowerShell JSON toolsReview package identity, match details, and database freshnessDo not collapse missing version/configuration evidence into not affected

Step-by-Step Tool Operation

  1. Choose an owned build directory with a known commit/build ID and a clear relationship to the deployed workload. Record which package manifests and installed artefacts are included. A source directory is not automatically a complete runtime inventory.
  2. Record tool versions and the vulnerability database status. If the approved DB is absent or stale, resolve that through the organisation's update or offline-import process before interpreting results.
  3. Generate a Syft JSON SBOM and a CycloneDX copy from the local directory using explicit file outputs. Preserve the source/build identity and both hashes; do not scan a remote image by an unpinned tag for this comparison.
  4. Run Grype against the existing SBOM, saving machine-readable output. Review match details, package release, fixed versions, advisory source, and ignored/suppressed status using the schema of the installed release.
  5. Ask the model for source-backed owner questions about version applicability, backports, feature prerequisites, exposure, and deployment. Do not fetch or execute public proof-of-concept code.
  6. After the owner-approved patch, regenerate the SBOM from the new actual build and repeat with a comparable database snapshot. Verify deployed digests and replicas separately from the scanner report.
syft version
grype version
grype db status
syft dir:.\owned-build -o syft-json=.\sbom.syft.json -o cyclonedx-json=.\sbom.cdx.json
if ($LASTEXITCODE -ne 0) { throw 'SBOM generation failed' }
grype sbom:.\sbom.syft.json -o json > .\grype-results.json
if ($LASTEXITCODE -ne 0) { throw 'Vulnerability matching failed; inspect the tool diagnostics' }
Get-FileHash .\sbom.syft.json -Algorithm SHA256
$Result = Get-Content -Raw .\grype-results.json | ConvertFrom-Json
$Result.matches | Select-Object -First 10 @{Name='Package';Expression={$_.artifact.name}}, @{Name='Version';Expression={$_.artifact.version}}, @{Name='Advisory';Expression={$_.vulnerability.id}}

Expected Evidence and Interpretation

A successful run produces inventory and match records, not a promise of any particular CVE count. Empty matches can mean no known matches in that database, incomplete inventory, or an unrecognised ecosystem; inspect coverage. Grype may contact database/update services according to configuration. Use the approved offline mode and data distribution process where network access is restricted, and record the exact DB revision.

For an illustrative match, confirm the vendor/distribution advisory and installed package release before classifying a backported build as vulnerable. The synthetic advisory lab earlier in the article remains the reproducible applicability exercise; the real tools supply inventory/matching inputs, not a universal version evaluator.

Troubleshooting and Cleanup

If the owned-build path is wrong, stop rather than substituting a production filesystem. If a fixed package still matches, inspect backports, stale SBOMs, old replicas, and database revisions. Keep SBOMs and reports private where they reveal sensitive technology. Remove temporary exports according to the engagement's retention policy, not by deleting the only evidence of the original decision.