Bawbel · Internal Engineering Reference
The Agentic Vulnerability Enumeration standard, explained at two levels: a high-level view for partners and decision-makers, and a detailed view for the engineers who author records, build scanners, and consume the output.
Section 1
Conventional vulnerability standards were built for conventional software.
CVE identifies a flaw, CVSS scores its severity, and OSV maps it to a specific package and version range. This works because traditional vulnerabilities live in code you can pin to a release.
Agent component threats do not. A prompt injection hidden in an MCP tool description, a skill file that fetches its real instructions from a remote URL, a rug pull that changes behavior after install, a toxic flow that chains two individually-benign capabilities into an exfiltration path — none of these map to a package and version. The same malicious behavior appears in infinitely many textual forms, and the danger is in what the component does, not which dependency it pulls. That is the gap: the existing standards are blind to it because there is no package to flag and no version range to constrain.
AVE is an open standard that assigns a stable identifier to each distinct behavioral vulnerability class in agentic AI. Each record describes the behavior that makes a component dangerous, scores it with OWASP AIVSS v0.8, and maps it to the frameworks the field already uses. It is behavioral, not signature-based — one record catches many textual variants of the same underlying attack. AVE is a standard, not a product: the Bawbel scanner implements it, but it is designed to be implemented by anyone.
Every record maps to OWASP MCP Top 10, OWASP Agentic AI Top 10, and MITRE ATLAS, scored with OWASP AIVSS v0.8. AVE does not replace a framework — it gives teams a lintable way to enforce one.
Independent studies find different agent-security scanners barely agree on what they flag. That is a vocabulary problem, not a quality one. AVE is the shared reference that makes cross-tool findings comparable.
A standard owned by one company invites lock-in fear. AVE is Apache 2.0 with an explicit path toward neutral governance as an OWASP project — meant to outlive any single implementation.
If the field adopts one vocabulary, findings from any tool interoperate and a security team can finally compare and correlate results across scanners. That is the position AVE is built to occupy — the CVE moment for AI agents.
Section 2
An AVE record is a single JSON file at records/AVE-YYYY-NNNNN.json that validates against schema/ave-record.schema.json (currently v1.1). It has two conceptual halves.
The static definition describes the vulnerability class itself and never changes per scan. ave_id is immutable — once published it is never renumbered or reused; a wrong record is deprecated via status, never deleted. behavioral_fingerprint is the heart of the record: it describes what the component does, not a byte signature. Severity and aivss_score must agree — CRITICAL implies a score of 9.0 or higher.
The evidence declarations were added in schema v1.1 (issues #69–72). They are all optional, so every pre-v1.1 record still validates. Crucially, they do not carry per-detection values — they declare the defaults and baselines a scanner uses to assign per-finding evidence metadata.
A definition nobody can detect is not useful, and a detection with no false-positive guard is a liability. Every record therefore requires three things beyond the JSON:
pattern, yara, or semgrep) that implements detection and references the ave_id.The tooling in scripts/ enforces that every record has a rule and every rule has both fixtures. pytest runs the rules against the fixtures and fails if a positive fixture stops triggering or a negative fixture starts.
This is the most important concept for anyone implementing AVE, and the reason the v1.1 evidence fields exist.
An AVE record is static. A scanner Finding is a runtime instance — one detection of one file at one moment. Confidence belongs to the Finding, never to the record: the same class detected in a docs/ folder and in a live skill file deserves different confidence. So the record never carries a confidence number. It declares the baseline, and the scanner does the per-detection math.
| Record declares — static | Scanner assigns to Finding — runtime | |
|---|---|---|
| confidence_baseline | → | confidence (then FP-adjusted) |
| evidence_kind_default | → | evidence_kind |
| detection_stage | → | evidence_stage (floor) |
| evidence_basis_engines | → | evidence_basis |
| derivable_into | → | ToxicFlow.derived_from_findings |
In any Finding, confidence and aivss_score are separate fields with separate meaning and are never merged or substituted. AIVSS answers "how bad would this be"; confidence answers "how sure are we." A HIGH-severity low-confidence finding and a HIGH-severity high-confidence finding demand different responses, and the output keeps them distinct.
If the scanner hardcoded these baselines, a second implementation would invent its own and the two tools would produce divergent evidence metadata for the same class. Baselines belong in the standard so every implementation agrees. See docs/adr/0003-records-declare-baselines.md.
These are per-detection runtime values. They live only on the scanner Finding, never in an AVE record: confidence, confidence_band, the actual evidence_stage reached, confidence_reason, derived, line, match, suppressed, and the engine that actually fired.
ave_id in ruleId and referenced under taxonomies, plus aivss_score, confidence, owasp_mcp, and mitre_atlas in the properties bag. Because SARIF is already consumed by the GitHub Security tab and CI, AVE ids travel into those surfaces for free.sync_records.py export and served at api.piranha.bawbel.io and the public registry at ave.bawbel.io.