OWASP Xpsd

OWASP Xpsd is an AI agent that reads your code through read-only tools and decides which scanner findings or a signle CVE are actually reachable. Ultimately, it generates SARIF output on your Github's Security tab.

About OWASP Xpsd

The problem

An external report or a scanner can tell you a vulnerable package version is present. It cannot tell you whether the vulnerable function is ever called, let alone whether attacker-controlled input can reach it. So the one finding that matters sits in the same list as fifty that do not.

Xpsd closes that gap. For each finding it gives a language model a set of read-only code-analysis tools and returns a structured verdict with file and line evidence.

scanner report → select findings → one agent session per finding → verdict JSON → SARIF → GitHub Security tab

How it works

  • One session per finding. A ReAct loop: the model states what it needs to learn, calls one tool, reads the result, and repeats until it has a verdict or runs out of budget.

  • No shell, no filesystem. Every fact arrives through a tool call. The repository is never loaded into the model's context; it sees only the lines that bear on the question.

  • The toolkit. ast-grep for structural search, call sites, definitions and cross-references; file and grep access confined to the repository tree; OSV.dev lookups; page rendering for fixing commits and bug trackers; dependency fetching to pull a pinned upstream version into the sandbox when a component is built rather than vendored.

  • Cheapest question first. Is our version in the affected range? Is the vulnerable symbol used at all? Can external input reach it? Most findings exit at the first or second gate, so a full run costs a fraction of the worst case.

  • Budgets. Each session has a tool-call budget and a context-token budget; whichever is hit first stops further calls and asks for an answer from the evidence so far. Oversized results are truncated, duplicate calls are blocked, and the project layout is mapped once per run, not once per finding.

Adversarial review

  • Every decisive verdict is re-examined by a second, shorter session whose job is to challenge it.

  • Reachable? The reviewer looks for an edge in the call path that is never taken, or a condition that cannot open.

  • Not reachable? It checks that the stated blocker holds and searches for paths the first pass missed.

  • The reviewer uses source tools only, under its own compact budget. On disagreement its conclusion prevails; the original rationale stays in the verdict.

Inputs

  • Scan mode auto-detects Grype, Trivy, OSV-Scanner and Snyk JSON, and any SARIF 2.1.0 report. One verdict per finding.

  • Single-CVE mode takes one vulnerability description.

  • Filters run before any model call: dedupe and OSV enrichment, then severity, CVSS floor, network attack vector (AV:N), known exploitation (CISA KEV, VulnCheck KEV, ExploitDB, Metasploit, Nuclei, GitHub PoCs) or an explicit ID list, up to a configurable cap.

  • Guidance file. Facts that live outside the code (what gets compiled, what ships, what faces a network) go in as ground truth. The model prioritises them over generic assumptions and still cites the code.

Outputs

  • Verdict JSON: reachability (yes, no, uncertain), confidence, detected version and whether it is in range, whether the vulnerable code is present, the affected component, the call path from entry point to vulnerable use, evidence with file, line and notes, and the full rationale.

  • Markdown report with the same information and an attack-flow graph.

  • SARIF for GitHub code scanning. Reachable findings are errors at full CVSS severity; uncertain or failed analyses are warnings for review; ruled-out findings become notes with lowered severity, with the original score, reasoning and evidence still attached. Re-runs refresh alerts in place, and fail-on can gate the build on reachable or uncertain verdicts.

A verdict is a model judgement, not a formal proof. Read it with its confidence score, and treat uncertain as "needs a human", not "no".

Cost

  • Every run ends with a usage summary: tokens sent, tokens in context, model requests and tool calls, split between analysis and review, plus the billed cost.

  • On GitHub Copilot the cost is the exact sum of Copilot's own usage figures, not an estimate. With a bring-your-own-key provider the summary says when billing data is unavailable rather than guessing.

Running it

  • Ships as a Docker image, a host wrapper that mounts the source tree read-only, and a GitHub Action.

  • Model-agnostic: the Action runs natively on GitHub Copilot with the workflow's built-in token, or with Anthropic, OpenAI or Azure API keys.

Security boundaries

  • Source: mounted read-only, every path confined to the root; symlinks pointing outside resolve back to the root.

  • Network: outbound fetches go through a loopback validating proxy that resolves each host once and dials only globally routable addresses, which blocks SSRF against loopback, private and link-local ranges, redirect chains and DNS rebinding.

  • Execution: none by default.

  • Advisory text, fetched pages, scan reports and third-party source are untrusted. The boundaries stop them abusing the tools; they cannot stop them biasing the verdict. Do not treat "not reachable" as sole authority for a high-impact decision.

Links

Licence: Apache 2.0.

Project Resources

Project Leaders

Mehrun Hunter P.

Email

Shahriyar Jalayeri

Email

Project Information

Incubator Project
Classification
Tool
Language
Go
License
Apache License 2.0
Contributors
3
GitHub Stars
5
Downloads
0
OWASP Logo
OWASP is a nonprofit foundation improving software security through open-source projects, global communities, and education. All resources are free and open to everyone.
OWASP, the OWASP logo, and Global AppSec are registered trademarks and AppSec Days, AppSec California, AppSec Cali, SnowFROC, OWASP Boston Application Security Conference, and LASCON are trademarks of the OWASP Foundation, Inc.
© 2026, OWASP Foundation Inc. All rights reserved.
OWASP Xpsd | OWASP Foundation