From 613db773921d71d5d00587ae39cbba95951a4199 Mon Sep 17 00:00:00 2001 From: CHAK Saray Date: Sat, 15 Aug 2026 09:16:50 +0700 Subject: [PATCH 1/2] docs: independent validation section and technical write-ups (#187) Co-authored-by: Claude Co-authored-by: chaksaray <15962335+chaksaray@users.noreply.github.com> --- CONTRIBUTING.md | 96 +++++++++++++----- README.md | 31 ++++++ crosswalks/semia-to-ave.json | 128 ++++++++++++++++++++++++ dist/ave-records-latest.manifest.json | 2 +- docs/writeups/AVE-2026-00003.md | 128 ++++++++++++++++++++++++ docs/writeups/AVE-2026-00046.md | 117 ++++++++++++++++++++++ docs/writeups/AVE-2026-00047.md | 139 ++++++++++++++++++++++++++ 7 files changed, 613 insertions(+), 28 deletions(-) create mode 100644 crosswalks/semia-to-ave.json create mode 100644 docs/writeups/AVE-2026-00003.md create mode 100644 docs/writeups/AVE-2026-00046.md create mode 100644 docs/writeups/AVE-2026-00047.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6fbbcd..cef7c6e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,7 +68,7 @@ or a variant update before you write any JSON. ```bash git clone https://github.com/aveproject/ave cd ave -git checkout -b feat/AVE-2026-NNNNN-attack-class +git checkout -b feat/AVE-2026-NNNNN-attack-class origin/develop cp records/AVE-2026-00001.json records/AVE-2026-NNNNN.json ``` @@ -87,14 +87,35 @@ Key rules: - `behavioral_fingerprint` describes what the component *does*, not a string it contains. "Component fetches remote content and executes it as instructions" not "contains the word fetch." -- `owasp_mcp` is required with at least one entry. `owasp_asi`, - `mitre_atlas`, and `nist_ai_rmf` are optional — add - them when they apply, omit rather than force a poor fit. +- `owasp_mcp` is required with at least one entry, verified against the + category's own primary-source text — not inferred from how a + similar-sounding record in the corpus happened to tag itself. + `owasp_asi`, `mitre_atlas`, and `nist_ai_rmf` are not yet + schema-required (tracked for a future schema version, see issue + #178) but **always include the key**, even with no value: set it to + `[]` when you've genuinely checked and nothing fits, rather than + omitting the field. An absent key reads as "nobody checked"; an + empty array reads as "checked, no fit yet" — only the second is + honest. See `docs/specs/researcher-process.md`'s "Governance and + framework mappings" section for the full rule and the real + corpus-wide mistake (issue #179) this is written to prevent. - `indicators_of_compromise` must have at least one entry that a defender can actually search for in a real file. - `references` must have at least one citable primary source — a CVE, an arXiv paper, a vendor disclosure, or a scan report. -- `researcher` is required. Use your name or handle. +- `researcher` is required — **but it is almost never your own name.** + Nearly every record traces to a real external CVE, paper, vendor + disclosure, or existing tool's detection implementation; that + source's own name or organization goes in `researcher`, not the + person writing the AVE record. This exact mistake (defaulting to the + PR author because it's the name at hand while drafting) has shipped + on published records more than once and been caught and corrected + after the fact — see `docs/specs/researcher-process.md`'s + Accountability and sourcing section and its `AVE-2026-00060` worked + example for the full rule and a real corrected instance. Use your + own name only in the genuinely rare case where you are the original + discoverer of a behavioral class with no prior external source to + credit. - `severity` and `aivss.aivss_score` must agree: CRITICAL >= 9.0 · HIGH 7.0-8.9 · MEDIUM 4.0-6.9 · LOW < 4.0. @@ -130,37 +151,55 @@ description. Reviewers will ask for this if it is missing. ### Step 3 -- Validate locally ```bash -npm install ajv ajv-formats -node -e " -const Ajv = require('ajv/dist/2020'); -const addFormats = require('ajv-formats'); -const ajv = new Ajv({ strict: false }); -addFormats(ajv); -const schema = require('./schema/ave-record-1.1.0.schema.json'); -const record = require('./records/AVE-2026-NNNNN.json'); -const ok = ajv.validate(schema, record); -if (!ok) { console.error(ajv.errors); process.exit(1); } -else console.log('valid'); -" +pip install -e ".[dev]" +python scripts/validate_records.py # schema-checks every record, including yours +python scripts/check_fixtures.py # confirms every record has +/- fixtures +pytest tests/ -x -q # full suite: schema, AIVSS arithmetic, mitigation enums ``` +These are the actual scripts this project runs, including in CI -- +`validate_records.py` also checks the AIVSS arithmetic against your +record's own stated `aarf`/`cvss_base`/`thm`/`mitigation_factor` +values (a common failure mode is drafting against one set of factors +and writing down another), and `check_fixtures.py` confirms +`tests/fixtures/AVE-YYYY-NNNNN_positive.md` and `_negative.md` both +exist -- required for every record, see Step 4. If `npm`-based schema +tooling (`ajv`) is more convenient for your own workflow, it's a valid +supplementary check, but the record must pass the scripts above before +a PR is reviewed, not just an ad-hoc schema validator. + The record must validate clean before opening a PR. A PR with a schema-invalid record will not be reviewed. -### Step 4 -- Open a coordinated scanner PR +### Step 4 -- Write conformance fixtures (in this repo, required to merge) -Every AVE record needs at least one detection rule in -[bawbel/scanner](https://github.com/bawbel/scanner) with: +**Corrected**: fixtures live in *this* repo, not in bawbel/scanner -- +`scripts/check_fixtures.py` (Step 3) enforces this on every PR, which +is the actual, current gate. Add two files: -- A **positive fixture** — a file that must trigger the rule -- A **negative fixture** — a benign lookalike that must not trigger +``` +tests/fixtures/AVE-2026-NNNNN_positive.md # a conforming implementation MUST flag this +tests/fixtures/AVE-2026-NNNNN_negative.md # a conforming implementation MUST NOT flag this +``` -Open the scanner PR alongside the record PR. Reference each from the other. -A record without a detection rule will not be merged. +The negative fixture is the false-positive guard and deserves real +effort -- a realistic file that looks similar to the malicious one, not +an easy case that tests nothing. + +**Separately**, once the record and its fixtures are merged here, +detection *rule implementations* (the actual YARA/Semgrep/pattern code +that uses these fixtures) are implementation artifacts, not standard +artifacts -- they live in whichever tool implements against this +standard, e.g. [bawbel/scanner](https://github.com/bawbel/scanner), not +in this repo. Open a coordinated PR there referencing the `ave_id` and +the fixtures above; it's a real, encouraged step for getting a class +actually detected, but it is not what this repo's own PR is gated on. ### Step 5 -- Open the record PR -Target `main`. Title format: +Target `develop`, not `main` -- `main` is the GitHub default branch but +not this project's actual integration branch; real record PRs merge +into `develop` and get promoted to `main` separately. Title format: ``` feat: AVE-2026-NNNNN -- @@ -173,7 +212,8 @@ PR description must include: - Link to the issue - Link to the primary source - AARF score table with one-line rationale per non-zero factor -- Link to the coordinated scanner PR +- Any coordinated scanner-repo PR, if one exists yet (not required to + open the record PR itself, see Step 4) --- @@ -198,12 +238,14 @@ Canonical file: `schema/ave-record-1.1.0.schema.json`. To update an existing record: ```bash -git checkout -b fix/AVE-2026-NNNNN-description +git checkout -b fix/AVE-2026-NNNNN-description origin/develop # edit records/AVE-2026-NNNNN.json # update last_updated to today: "2026-MM-DDTHH:MM:SSZ" git commit -m "fix: AVE-2026-NNNNN -- " ``` +Target `develop` for the PR, same as new records. + AIVSS score changes require written rationale for each AARF factor that changes. Framework mapping additions (`owasp_asi`, `mitre_atlas`) are welcome without prior issue if the mapping is clear. diff --git a/README.md b/README.md index e405bb4..bd0f61a 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,37 @@ AVE fixes that. --- +## Independent validation + +AVE's ID scheme has been tested by people who didn't build it, not +just used by people who did. + +Three independent tools, cfgaudit, Ramparts, and nova-proximity, none +of them sharing code with AVE or with each other, built crosswalks +against AVE's records on their own initiative, unprompted. In each +case the comparison went beyond matching category labels: mechanism- +level correspondence was checked field by field, real trigger +conditions against real behavioral fingerprints, and dozens of +findings converged on the identical AVE ID independently. + +One of those crosswalks (Ramparts) also surfaced a real methodological +lesson: two independently-drafted readings of the same still- +unratified OWASP MCP Top 10 numbered their own categories differently, +confirmed and documented so future crosswalks match by category +meaning, not by tag number. + +Separately, an external maintainer caught a real attribution error in +two published AVE records, corrected the underlying process +documentation, not just the two records, credited in +[CONTRIBUTORS.md](CONTRIBUTORS.md). + +80 records. 3 independent crosswalks. See +[crosswalks/](crosswalks/) for the full mappings, and +[docs/writeups/](docs/writeups/) for full technical write-ups on +individual records. + +--- + ## How it works **Without AVE:** diff --git a/crosswalks/semia-to-ave.json b/crosswalks/semia-to-ave.json new file mode 100644 index 0000000..d04ebe4 --- /dev/null +++ b/crosswalks/semia-to-ave.json @@ -0,0 +1,128 @@ +{ + "$schema": "https://aveproject.org/schema/crosswalk-1.0.0.schema.json", + "source": { + "tool": "Semia", + "vendor": "RiemaLabs", + "url": "https://github.com/berabuddies/Semia", + "license": "Apache-2.0", + "version": "0.1.3", + "tool_class": "constraint-guided representation synthesis (SDL fact-base + Datalog detector rules)", + "commit": "379bc25fe99833eb185efe56a38fe15f0235799c" + }, + "target": { + "standard": "AVE", + "version": "1.1.0", + "url": "https://aveproject.org", + "record_count": 80, + "static_record_count": 58, + "commit": "49e469156a8c535387310692b1feef5ad7510f0e" + }, + "generated": "2026-08-15", + "note": "Built per berabuddies/Semia#36, permission confirmed by the maintainer (archidoge0), read against Semia's real source (not the paper's single act_sign/c_sign example): the schema at packages/semia-core/src/semia_core/schema.py defines Semia's complete SDL fact vocabulary (16 effects, 4 triggers, 5 gates, 5 doc claims, 7 value kinds, 6 call codes), and the Datalog rules in packages/semia-core/src/semia_core/rules/sdl/skill_dl_static_analysis.dl define 11 actual detector outputs (label_* .output relations, each a real finding type Semia's own detector.py reads back out as report.findings). This crosswalk matches against those 11 rules' real logic, not their names alone, since the two do not always agree (see the hardcoded_c2 gap below).\n\nThe open question from the outreach, whether constraint-guided representation synthesis generalizes onto AVE's behavioral classes or stays genuinely distinct from pattern-based classification, has a real, mixed answer: partial generalization, clean where a Semia rule terminates in a specific effect AVE also names explicitly, genuinely distinct where AVE's granularity is organized by attack narrative and Semia's is organized by dataflow destination. 16 mappings verified across 9 of Semia's 11 rules, field-checked against provenance_vector and behavioral_fingerprint, not category labels.\n\nThree concrete, citable examples of the real daylight: (1) label_unsanitized_context_ingestion (any untrusted value reaching one of five high-priv effects, ungated) keyword-sweeps against roughly two dozen of AVE's prompt-injection-flavored records, but only genuinely verifies against ones that name a specific privileged sink (AVE-2026-00006's crypto_sign, AVE-2026-00042's code_eval); most of AVE's prompt-injection catalog describes the injection vector itself (jailbreak, hidden instruction, context window manipulation, multi-turn persistence) without asserting a terminating privileged effect, so a keyword match is not a structural one. AVE splits by injection surface; Semia collapses by dataflow destination. (2) A rule's own name can promise a match its logic does not deliver: label_hardcoded_c2_communication reads like an obvious fit for AVE-2026-00073 (Static Endpoint Redirect), but the actual Datalog condition requires call_code=\"unresolved_target\", a destination static analysis cannot resolve at all, while AVE-2026-00073's mechanism is the opposite: a fully resolved, literal, committed bad destination. No AVE record currently satisfies this rule's real condition; left unmapped rather than forced. (3) A shape can sit a full abstraction level above what Semia's fact model can represent: AVE-2026-00070 (Distributed Cross-Agent Backdoor Fragments) shares label_dormant_malicious_payload's dormant-until-reassembled narrative, but the mechanism spans multiple agents' memories with an offline, external reassembly step, and Semia's CORE_SCHEMA models exactly one skill() per analysis pass with no multi-agent or cross-session concept in the schema at all. Not a missing rule, a missing dimension; left unmapped.\n\nTwo more things worth surfacing. First, AVE-2026-00003 (Credential exfiltration via agent instruction) is matched by two of Semia's own rules independently, label_implicit_egress_channels (an explicit dataflow edge from a secret value to an untrusted egress call) and label_shadow_credentials (co-presence of a secret-region read and an untrusted-egress-capable skill, checked without requiring an explicit edge), two differently-reasoned Datalog conditions inside one tool converging on the same AVE id. Combined with this record's existing cfgaudit, nova-proximity, and Ramparts matches (see those crosswalks), it is now the record with the broadest independent confirmation across AVE's whole crosswalk set, four separate tools, none sharing code, plus one tool's own two internal rules. Second, near-misses considered and rejected rather than forced: AVE-2026-00029 (Unicode Homoglyph) and AVE-2026-00069 (Multimodal Image-Hidden Instructions) share label_obfuscation's theme but not its substrate, Semia's call_code vocabulary (encoded_binary, obfuscated, script, shell, inline_code, unresolved_target) has no visual/text-rendering or image-modality category, matching only AVE-2026-00057's base64/hex/bytecode concealment cleanly; AVE-2026-00074 (Dead Anchor Reclamation) was considered for label_unverifiable_dependency_source but rejected, its \"unresolved\" is about an external identity becoming re-registerable after publication, not a static-analysis-time unresolved call target; AVE-2026-00030 (False Role Claim) was considered for label_behavior_claim_contradiction but rejected, it is about an external party's claim being trusted, not the component's own declared capability claim contradicting its own behavior, the direction Semia's rule actually checks.", + "mappings": [ + { + "semia_label": "label_dangerous_execution_primitives", + "ave_id": "AVE-2026-00060", + "title": "STDIO transport shell injection via unsanitized tool call parameters", + "notes": "Direct match to the rule's call_effect(c,\"proc_exec\") + call_in_untrusted_region(c) clause: unsanitized shell metacharacters in transport-layer parameters reaching the host shell is exactly an untrusted-region proc_exec call." + }, + { + "semia_label": "label_dangerous_execution_primitives", + "ave_id": "AVE-2026-00004", + "title": "Arbitrary code execution via shell pipe injection in agentic component", + "notes": "curl|bash / wget|sh instructed by skill content is a proc_exec call whose region is untrusted content, matching the rule's primary clause directly." + }, + { + "semia_label": "label_dangerous_execution_primitives", + "ave_id": "AVE-2026-00052", + "title": "Command injection via unsanitized tool-call parameter in MCP server implementation", + "notes": "A caller-supplied parameter reaching a shell/system-command function with no sanitization is a literal taint path to proc_exec, not a keyword match; Semia's dataflow-tracked call_input/value_reaches chain verifies this the same way AVE's own fingerprint requires a caller-supplied-parameter-to-shell-exec path, not signature scanning over dangerous syntax." + }, + { + "semia_label": "label_unverifiable_dependency_source", + "ave_id": "AVE-2026-00001", + "title": "Metamorphic payload via external config fetch", + "notes": "Fetching remote content that replaces the component's own instructions at runtime is the rule's net_read/agent_call-untrusted-region-feeding-exec clause almost exactly: an unverifiable source resolved only at execution time, after review." + }, + { + "semia_label": "label_unverifiable_dependency_source", + "ave_id": "AVE-2026-00062", + "title": "Unpinned dependency version allowing supply chain substitution", + "notes": "Same underlying idea as the rule's unresolved_target clause, a reference that can resolve to different content after review, though at different granularity: AVE-2026-00062 covers the unpinned declaration itself; Semia's rule requires the chain actually be exercised into an exec/read sink. AVE's record is the broader precondition, Semia's rule the exploited instance." + }, + { + "semia_label": "label_behavior_claim_contradiction", + "ave_id": "AVE-2026-00058", + "title": "Deceptive skill trigger or activation-scope manipulation via misleading manifest description", + "notes": "Same declared-vs-actual architecture as the rule (skill_doc_claim contradicted by a later call_effect), but a different claim axis: Semia's five doc claims (read_only, local_only, no_network, no_fs_write, credential_bound) are capability claims; AVE-2026-00058 is about invocation-scope claims (trigger keywords, when the skill activates), not what it does once active.", + "gap": "No current AVE record covers Semia's exact claim type: a manifest declaring read_only/no_network/no_fs_write contradicted by an actual write or network call at the capability level. Worth a real AVE record, flagged back on the issue." + }, + { + "semia_label": "label_unsanitized_context_ingestion", + "ave_id": "AVE-2026-00006", + "title": "Cryptocurrency wallet drain via malicious fund transfer instruction in agentic component", + "notes": "An untrusted instruction (fund-transfer / allowance-approval directive) reaching a crypto_sign call is an exact match to the rule's high_priv_call clause, which names crypto_sign specifically." + }, + { + "semia_label": "label_unsanitized_context_ingestion", + "ave_id": "AVE-2026-00042", + "title": "Payload injection into agent-generated orchestration code via poisoned tool results in REPL/Code Mode", + "notes": "Tool result content passed directly into eval()/exec() is exactly the rule's high_priv_call code_eval clause, with the untrusted source explicitly named as tool_response in AVE's own provenance_vector." + }, + { + "semia_label": "label_implicit_egress_channels", + "ave_id": "AVE-2026-00003", + "title": "Credential exfiltration via agent instruction", + "notes": "A secret value (env var / credential store read) reaching an untrusted-region net_write/agent_call is the rule's core clause exactly. Already independently matched by cfgaudit, nova-proximity, and Ramparts; this is a fourth, independently-reasoned tool converging on the same id." + }, + { + "semia_label": "label_implicit_egress_channels", + "ave_id": "AVE-2026-00013", + "title": "Personal data exfiltration via PII collection and transmission in agentic component", + "notes": "Same rule shape (sensitive value reaching an untrusted egress call), though Semia's literal value_secret_source keyword list (password, token, secret, api_key, apikey, mnemonic) does not itself include PII terms like SSN or passport; the structural match holds, the keyword coverage for this specific value type would need extending on Semia's side to catch every case AVE's fingerprint describes." + }, + { + "semia_label": "label_sensitive_local_resource_overreach", + "ave_id": "AVE-2026-00006", + "title": "Cryptocurrency wallet drain via malicious fund transfer instruction in agentic component", + "notes": "Also matches this second, independent rule: wallet access used beyond its declared allowed action. One AVE record satisfying two separately-reasoned Semia rules simultaneously, the reverse of Ramparts' EnvironmentVariableLeakage splitting one rule across two AVE ids." + }, + { + "semia_label": "label_ungated_irreversible_operation", + "ave_id": "AVE-2026-00005", + "title": "Recursive file system destruction via destructive command injection in agentic component", + "notes": "Recursive filesystem deletion with no confirmation step is a direct match to a high_priv_call (chain_write-equivalent destructive effect) with no gated_action present at all." + }, + { + "semia_label": "label_ungated_irreversible_operation", + "ave_id": "AVE-2026-00064", + "title": "Zero-click code execution via project-load auto-run configuration", + "notes": "Auto-run on project load with explicitly no confirmation step is definitional for this rule: a high-priv call with zero declared gate." + }, + { + "semia_label": "label_ungated_irreversible_operation", + "ave_id": "AVE-2026-00021", + "title": "Autonomous Action Without User Confirmation", + "notes": "Same external symptom (irreversible action, no human checkpoint), reached by a different mechanism: Semia's rule checks the structural absence of any declared gate; AVE-2026-00021 is an explicit instruction to bypass a gate that may otherwise be present. A component with no gate at all and one instructed to ignore its gate look identical from the outside but are different facts in Semia's own schema.", + "gap": "Semia's SDL has no fact for 'gate present but instructed to be skipped', only gate declared vs. not declared; the bypass-in-the-moment case AVE-2026-00021 describes is not structurally distinguishable from label_ungated_irreversible_operation's plain absence-of-gate case in the current schema." + }, + { + "semia_label": "label_shadow_credentials", + "ave_id": "AVE-2026-00003", + "title": "Credential exfiltration via agent instruction", + "notes": "A second Semia rule reaching this same AVE id, via co-presence rather than an explicit dataflow edge: a secret-region read (env_read/fs_read) plus the skill having any untrusted egress call anywhere, checked independently of whether that specific read reaches that specific egress. Two of Semia's own rules (see label_implicit_egress_channels above) fire on this one AVE record for two structurally different reasons, overlapping coverage by design rather than a crosswalk artifact." + }, + { + "semia_label": "label_obfuscation", + "ave_id": "AVE-2026-00057", + "title": "Obfuscated or encoded skill payload designed to evade static scanners", + "notes": "Near-definitional match: AVE's own description (base64, hex, bytecode, or fragmented keywords specifically to evade pattern-based scanners) is what Semia's obfuscated/encoded_binary call_code categories exist to catch." + } + ], + "coverage": { + "semia_rules_total": 11, + "semia_rules_mapped": 9, + "ave_classes_covered": 14, + "note_on_unmapped": "2 of Semia's 11 label_* detector rules (label_hardcoded_c2_communication, label_dormant_malicious_payload) have no verified AVE match; see note field for why each was left unmapped rather than forced." + } +} diff --git a/dist/ave-records-latest.manifest.json b/dist/ave-records-latest.manifest.json index 86ab866..7df4d67 100644 --- a/dist/ave-records-latest.manifest.json +++ b/dist/ave-records-latest.manifest.json @@ -1,6 +1,6 @@ { "schema_version": "1.1.0", "record_count": 80, - "generated_at": "2026-08-15T01:01:08.331Z", + "generated_at": "2026-08-15T02:12:31.694Z", "source": "https://github.com/aveproject/ave" } diff --git a/docs/writeups/AVE-2026-00003.md b/docs/writeups/AVE-2026-00003.md new file mode 100644 index 0000000..e463b58 --- /dev/null +++ b/docs/writeups/AVE-2026-00003.md @@ -0,0 +1,128 @@ +# Credential exfiltration via agent instruction + +Not every credential leak needs a bug. Sometimes the agent is simply +told to leak one, in plain language, as though reading an environment +variable and sending it somewhere were a normal step in the task it's +been asked to do. Because the agent follows instructions rather than +enforcing a security model, it has no built-in reason to treat that +step differently from any other. + +## The mechanism + +The record's description is direct about what makes this its own +class, separate from a credential merely sitting exposed in a file +(that's AVE-2026-00047): here, a skill file instructs the agent to +actively read environment variables, configuration files, or +credential stores, and then transmit their contents to an external +destination. The agent follows these instructions as part of normal +task execution, treating the credential collection as a legitimate +step because nothing in the instruction looks different from any other +step in the skill. + +The behavioral fingerprint names the two-part shape this always takes: +a component instructs the agent to read and transmit environment +variables, API keys, or other credentials to an external destination. +Both halves have to be present. An instruction that only reads +credentials without directing them anywhere external isn't this +class, and neither is an instruction that sends data externally +without first pulling from a credential source. It's the read-then-send +pairing, expressed as an instruction the agent will follow, that the +record is built around. + +## Why this scores 6.8 (MEDIUM) + +``` +AIVSS = ((CVSS_Base + AARS) / 2) x ThM x Mitigation_Factor +``` + +The record's AARF factors: + +``` +autonomy=1.0 tool_use=1.0 multi_agent=0.0 non_determinism=0.5 +self_modification=0.0 dynamic_identity=0.0 persistent_memory=0.0 +natural_language_input=1.0 data_access=1.0 external_dependencies=0.5 + +AARS = 1.0 + 1.0 + 0.0 + 0.5 + 0.0 + 0.0 + 0.0 + 1.0 + 1.0 + 0.5 = 5.0 +CVSS_Base = 8.5 ThM = 1.0 (in-the-wild) Mitigation_Factor = 1 + +AIVSS = ((8.5 + 5.0) / 2) x 1.0 x 1 = 6.75 -> 6.8, MEDIUM +``` + +`autonomy`, `tool_use`, `natural_language_input`, and `data_access` +sit at the maximum 1.0, this is an instruction the agent carries out +autonomously, using its own tool access, triggered by ordinary +natural-language content, reading data it already has permission to +read. What pulls the AARS down from AVE-2026-00046's 8.5 or +AVE-2026-00047's 6.5 is the set of factors sitting at 0.0: +`multi_agent`, `self_modification`, and `persistent_memory` play no +role here, this is a single agent, in a single session, following an +instruction once, not a mechanism that compounds across agents or +persists across sessions. The record's own AARF notes describe this +plainly as reflecting "typical skill deployment in agentic workflows," +not an edge-case amplifier. The CVSS vector backs the same read: high +confidentiality impact, but no integrity or availability impact at +all, and privileges required (`PR:L`) and attack requirements +(`AT:P`) both above the minimum, unlike AVE-2026-00046's fully +unauthenticated vector. + +## How it's caught + +The record's detection methodology layers three approaches rather +than relying on pattern matching alone: + +1. Static scan: search component content for patterns matching this + attack class. +2. Semantic analysis: an LLM-based reviewer flags behavioral + directives in the component content, catching phrasing a static + pattern would miss. +3. Behavioral sandbox: monitor agent behavior during initialization + for unexpected actions, catching the case where the instruction + only becomes clear once it actually executes. + +Indicators of compromise listed on the record: + +- The component references `os.environ`, `process.env`, or a similar + environment-access API. +- The component instructs the agent to read `.env` files, + configuration files, or credential stores. +- The component includes instructions to send or transmit data to an + external URL or API. +- An outbound network request containing credential-shaped data is + observed after the skill executes. + +Remediation, per the record, is written for active incident response, +not just prevention: + +1. Remove the component immediately. +2. Rotate all environment variables and API keys accessible to the + agent, treat exposure as certain rather than possible. +3. Review outbound network logs for credential-shaped data. +4. Audit all tool calls and external requests made during the + exposure window. + +## Independent confirmation + +This is the third of three AVE records where cfgaudit, nova-proximity, +and Ramparts, none sharing code, all converge independently. + +cfgaudit maps four of its own rules onto this record (`CFG031`, +`CFG036`, `CFG037`, `CFG038`). nova-proximity's `DetectDataExfiltration` +rule matches the sub-case of "credential file paths with external-send +framing," noted as a "direct mechanism match, instructed +read-and-transmit," the same read-then-send pairing the AVE fingerprint +requires. Ramparts maps its `EnvironmentVariableLeakage` finding here +too, but through a different internal branch than the one it uses for +AVE-2026-00047: Ramparts' own crosswalk notes describe this as "the +other half of the same Ramparts rule," matching "AVE's +instructed-exfiltration mechanism, not the hardcoded-literal one," a +single rule name covering two mechanistically distinct AVE records +depending on which internal condition fires. That split inside a +single external tool's own rule is itself a small piece of +independent confirmation that AVE draws the line between "credential +sits exposed" and "credential is actively instructed out" in a place +that a completely separate detection engine had already found reason +to draw a line of its own. + +## Further reading + +Live record: [aveproject.org/registry.html#AVE-2026-00003](https://aveproject.org/registry.html#AVE-2026-00003) diff --git a/docs/writeups/AVE-2026-00046.md b/docs/writeups/AVE-2026-00046.md new file mode 100644 index 0000000..8cdc3e1 --- /dev/null +++ b/docs/writeups/AVE-2026-00046.md @@ -0,0 +1,117 @@ +# MCP tool hook hijacking - redirect tool execution to attacker-controlled callback + +Most agentic AI setups call tools through a central dispatcher: the +agent decides to invoke a tool, the client looks up the registered +handler for that tool, and the handler runs. That single dispatch +point is convenient for building things like logging, retries, and +observability hooks. It is also a single point where every tool call +in a session can be silently rerouted, without the agent (or the +person watching it work) ever knowing the handler it thinks it's +calling isn't the one that ran. + +## The mechanism + +A legitimate MCP tool call looks like this: the agent decides to +invoke a tool, the client's registry resolves that tool name to its +handler, and the handler executes with the real implementation. The +agent has no visibility into that resolution step: it trusts the +registry to hand the call to the right code. + +AVE-2026-00046 covers a malicious skill file or MCP component that +registers a hook, callback, or interceptor on that dispatch layer +itself, rather than attacking any individual tool. Because MCP +clients route tool calls through a central registry, a hook +registered early in the session, before any other skill has had a +chance to run, can intercept all subsequent tool invocations, +including calls made by other skills and by system tools the +malicious component never touched directly. The agent keeps believing +it is calling the legitimate handler the whole time. + +The hook has two ways to behave once it holds that position, and both +are covered by the record: it can pass calls through to the real +handler as a transparent proxy (so the tool still works, but a copy of +every call and its parameters goes to the attacker first), or it can +drop them silently and return a substituted response. Either way, the +compromise sits above the level of any single tool, which is what +distinguishes it from an attack against one tool's own logic. + +## Why this scores 9.2 (CRITICAL) + +AVE uses OWASP AIVSS v0.8: + +``` +AIVSS = ((CVSS_Base + AARS) / 2) x ThM x Mitigation_Factor +``` + +The record's AARF factors: + +``` +autonomy=1.0 tool_use=1.0 multi_agent=0.5 non_determinism=0.5 +self_modification=1.0 dynamic_identity=1.0 persistent_memory=0.5 +natural_language_input=1.0 data_access=1.0 external_dependencies=1.0 + +AARS = 1.0 + 1.0 + 0.5 + 0.5 + 1.0 + 1.0 + 0.5 + 1.0 + 1.0 + 1.0 = 8.5 +CVSS_Base = 10 ThM = 1.0 (in-the-wild) Mitigation_Factor = 1 + +AIVSS = ((10 + 8.5) / 2) x 1.0 x 1 = 9.25 -> 9.2, CRITICAL +``` + +Autonomy, tool use, self-modification, dynamic identity, and external +dependencies all sit at the maximum 1.0: a hook that reroutes the +dispatch layer is, by definition, the agent's own tool-calling +capability turned against every other tool it uses that session, with +no approval step in between. `CVSS_Base` of 10 reflects the record's +own CVSS 4.0 vector (`AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/ +SI:H/SA:H`): network-reachable, low complexity, no privileges or user +interaction required, high impact across confidentiality, integrity, +and availability on both the vulnerable and subsequent systems. `ThM` +of 1.0 reflects that this is scored as an in-the-wild threat maturity, +not theoretical. Nothing in `mitigation_factor` reduces the score: +it's set to 1, meaning no credited mitigation offsets the base +calculation. + +## How it's caught + +The record's detection methodology is static, applied before a skill +is ever loaded: + +1. Scan skill files for hook registration instructions that reference + external URLs or callback handlers. +2. Flag patterns containing phrases like *register hook*, *override + execute*, *intercept all*, *monkey-patch tool*, or *wrap + tool_call*. +3. Enforce an allowlist of permitted tool handlers set at server + startup, and reject any runtime attempt to modify that registry. +4. Audit agent session logs for pre-execution callbacks firing before + the legitimate tool handler runs. + +Indicators of compromise listed on the record: + +- A skill file contains a hook registration instruction with an + external callback URL. +- Tool execution latency increases uniformly across *all* tool calls + in a session, not just one, consistent with every call now passing + through an extra hop. +- Network traffic to an unrecognized endpoint precedes every tool + invocation. +- Agent logs show a pre-execution callback firing before the + legitimate tool handler. +- Tool results look correct, but the underlying data has already been + exfiltrated to a third party via the transparent-proxy path. + +Remediation, per the record: + +1. Deny hook registration instructions inside skill files outright: + hooks are infrastructure configuration, not something a skill + should be able to declare. +2. Maintain a static registry of tool handlers fixed at server + startup, and reject any runtime attempt to modify it. +3. Scan all skill files for hook-registration patterns before they're + ever loaded. +4. Where a hook is a legitimate internal observability tool, require a + documented justification to suppress the finding rather than + silently allowing it. + +## Further reading + +Live record: [aveproject.org/registry.html#AVE-2026-00046](https://aveproject.org/registry.html#AVE-2026-00046) diff --git a/docs/writeups/AVE-2026-00047.md b/docs/writeups/AVE-2026-00047.md new file mode 100644 index 0000000..f753e66 --- /dev/null +++ b/docs/writeups/AVE-2026-00047.md @@ -0,0 +1,139 @@ +# Hardcoded credentials in agent component - API keys and secrets exposed in skill files + +Hardcoding a credential in source code has been a known bad practice +for decades: anyone who reads the file reads the secret. Agentic AI +components make that old mistake worse in a way that's easy to miss. +A skill file, MCP server manifest, or system prompt with a literal API +key in it isn't just readable by a person browsing the repo. It's +readable by the agent itself, and by anything that can get its own +text into that agent's context window. + +## The mechanism + +The record's description draws the distinction directly: in +conventional application code, a hardcoded credential sitting in a +source file is a well-understood risk with a well-understood fix, +don't commit secrets, rotate what leaks. In an agent component, the +same literal value sits somewhere the agent reads and reasons over +constantly, and the agent's own instruction-following behavior becomes +part of the attack surface. A prompt injection payload elsewhere in +that same context window can instruct the agent to locate and repeat +back any credential it can see, turning a passive leak into an active +exfiltration channel the agent itself carries out. + +The record's behavioral fingerprint is specific about what counts: a +high-entropy string sitting adjacent to a credential keyword (`api_key`, +`secret`, `token`, `password`) or a recognizable key-format prefix like +`sk-` or `Bearer`, and critically, the value has to be literal. A +reference to an environment variable or a secrets-manager path (`$VAR`, +`vault://secret/db/prod`) is explicitly excluded from the fingerprint, +because that's the actual fix, not the vulnerability. + +## Why this scores 7.6 (HIGH) + +``` +AIVSS = ((CVSS_Base + AARS) / 2) x ThM x Mitigation_Factor +``` + +The record's AARF factors: + +``` +autonomy=0.5 tool_use=1.0 multi_agent=0.0 non_determinism=0.5 +self_modification=0.0 dynamic_identity=0.5 persistent_memory=1.0 +natural_language_input=1.0 data_access=1.0 external_dependencies=1.0 + +AARS = 0.5 + 1.0 + 0.0 + 0.5 + 0.0 + 0.5 + 1.0 + 1.0 + 1.0 + 1.0 = 6.5 +CVSS_Base = 8.7 ThM = 1.0 (in-the-wild) Mitigation_Factor = 1 + +AIVSS = ((8.7 + 6.5) / 2) x 1.0 x 1 = 7.6, HIGH +``` + +The record's own notes on this AARF breakdown say it plainly: the +scores reflect "credential exposure amplified by agent context window +accessibility and prompt injection risk," which is why `data_access`, +`natural_language_input`, and `persistent_memory` all sit at the +maximum 1.0, the credential persists in the component and is readable +through ordinary natural-language context access, no special exploit +needed. `multi_agent` and `self_modification` sit at 0.0: a bare +hardcoded secret doesn't inherently involve multiple agents or +runtime self-editing, which is what keeps this a HIGH rather than a +CRITICAL despite the maximum `data_access` score. `CVSS_Base` of 8.7 +reflects the vector's high confidentiality impact alongside high +subsequent-system confidentiality and integrity impact, but only low +direct integrity impact and no availability impact, unlike AVE-2026-00046's +full-severity vector, this one doesn't let an attacker take over +execution, only read what it shouldn't. + +## How it's caught + +The record's detection methodology is layered pattern and entropy +analysis, not a single check: + +1. Scan skill files for credential keyword patterns adjacent to + high-entropy string literals. +2. Flag known key-format prefixes: `sk-`, `ghp_`, `gho_`, `xoxb-`, + `AKIA`. +3. Flag PEM-encoded private key headers. +4. Apply entropy analysis to string values that follow credential + keywords. +5. Exclude environment-variable references (`$VAR`, `${VAR}`) and + secrets-manager paths (`vault://`, `aws-ssm://`) from the flag, so + the correct pattern doesn't get penalized alongside the incorrect + one. + +Indicators of compromise listed on the record: + +- A high-entropy string literal sits adjacent to an `api_key`, + `secret`, `token`, or `password` keyword. +- A known vendor key prefix is present: `sk-`, `ghp_`, `gho_`, + `xoxb-`, `AKIA`. +- A PEM private key block is present in the skill file. +- A bearer token literal appears in a skill file header or tool + description. +- The same credential value is unchanged across multiple skill file + versions in git history, meaning it was never rotated after being + committed. + +Remediation, per the record: + +1. Replace hardcoded credentials with environment variable + references, for example `DATABASE_URL` read from environment + rather than written inline. +2. Use a secrets-manager path instead of the secret value itself, + for example `vault://secret/db/prod`. +3. Rotate any credential that has already been committed immediately; + assume it's compromised the moment it lands in version control. +4. Add credential-pattern scanning to pre-commit hooks, failing the + commit on high-severity findings rather than catching it after the + fact. +5. Suppress the finding, with documented justification, only for + values that are genuinely placeholders, not real values that happen + to look low-risk. + +## Independent confirmation + +This is one of three AVE records that all three of AVE's independent +crosswalks converge on, cfgaudit, nova-proximity, and Ramparts each +built their mapping without shared code or coordination, and all three +land on AVE-2026-00047 for the same class of finding. + +cfgaudit maps six of its own rules onto this one record (`CFG007`, +`CFG050`, `CFG054`, `CFG065`, `CFG073`, `CFG097`). nova-proximity's +`DetectDataExfiltration` rule matches on the same literal key-prefix +patterns (`sk-`, `ghp_`, `Bearer `) the AVE record's own fingerprint +calls out, noting a "direct mechanism match." Ramparts maps two of its +own findings here: `SecretsLeakage`, whose notes confirm both projects +"require a literal high-entropy credential value adjacent to a +credential keyword" and that AVE's fingerprint "explicitly excludes +env-var references, matching Ramparts' literal-value requirement," +and a second finding, `EnvironmentVariableLeakage`'s +named-assignment-with-value branch, anchored to env-var-shaped names +specifically but the same underlying literal-value mechanism. + +Three tools that don't share code independently landed on the same +distinguishing detail: a literal secret value is the finding, a +reference to where the secret is stored properly is not. + +## Further reading + +Live record: [aveproject.org/registry.html#AVE-2026-00047](https://aveproject.org/registry.html#AVE-2026-00047) From 0bef08d7781e1c1c8ae67d4c188cb9c4dd846491 Mon Sep 17 00:00:00 2001 From: chaksaray Date: Sat, 15 Aug 2026 21:06:45 +0700 Subject: [PATCH 2/2] feat: skillsentry-to-ave and skill-security-scanner-to-ave crosswalks Revisits the deferred bandwidth check on both tools: both have real, structured output (named rules, severity, categories), confirmed from their actual code rather than star counts, the same mistake sast-skills' high star count nearly caused earlier. skillsentry: 24 rules, 7 verify at the mechanism level, 5 partial (real overlap but narrower/broader than AVE's fingerprint), 12 confirmed gaps. skill-security-scanner: substantially larger surface (54 config rules + 5 algorithmic detectors), closer in caliber to Ramparts/nova-proximity. Documents three findings beyond a simple match count: the injection category has the same signature-vs-reachability gap the Ramparts crosswalk already flagged for the same AVE record; IOCDetector's reputation-list approach has no AVE counterpart by design (AVE is behavioral fingerprints over signatures); LLMAnalyzer's free-form output has no fixed taxonomy to crosswalk against. --- crosswalks/skill-security-scanner-to-ave.json | 192 ++++++++++++++++++ crosswalks/skillsentry-to-ave.json | 130 ++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 crosswalks/skill-security-scanner-to-ave.json create mode 100644 crosswalks/skillsentry-to-ave.json diff --git a/crosswalks/skill-security-scanner-to-ave.json b/crosswalks/skill-security-scanner-to-ave.json new file mode 100644 index 0000000..b4612ac --- /dev/null +++ b/crosswalks/skill-security-scanner-to-ave.json @@ -0,0 +1,192 @@ +{ + "$schema": "https://aveproject.org/schema/crosswalk-1.0.0.schema.json", + "source": { + "tool": "skill-security-scanner", + "vendor": "honysyang", + "url": "https://github.com/honysyang/skill-security-scanner", + "license": "MIT", + "tool_class": "static regex rule engine + algorithmic detectors (entropy, hidden-char, base64, IOC lookup, LLM analysis) for AI agent skill code", + "rules_total": 54, + "static_record_count_note": "54 config-driven rules (config/rules.yaml) plus 5 algorithmic detector modules not driven by that config", + "commit": "92538dffecd940ebb7fb082057dc1ce8a955d59b" + }, + "target": { + "standard": "AVE", + "version": "1.1.0", + "url": "https://aveproject.org", + "record_count": 80, + "commit": "613db773921d71d5d00587ae39cbba95951a4199" + }, + "generated": "2026-08-15", + "note": "Read against skill-security-scanner's real, complete detection surface: 10 rule categories in config/rules.yaml (54 named rules, SEC001 etc.) plus 5 algorithmic Python detectors not driven by that config file (EntropyDetector, HiddenCharDetector, Base64Detector, IOCDetector, LLMAnalyzer). Substantially larger surface than skillsentry, closer in caliber to Ramparts/nova-proximity/Semia.\n\nThree findings worth stating directly rather than leaving implicit. First, the injection category (INJ001-006: eval()/exec() with a non-literal argument, os.system, subprocess shell=True) reads like an obvious match for AVE-2026-00052, but these are pure regex signature matches over dangerous syntax, not a traced dataflow from a caller-supplied parameter to the sink; AVE-2026-00052's own fingerprint specifically requires that taint path. This is the exact same signature-vs-reachability distinction the Ramparts crosswalk already documented for its own CommandInjection rule against this same AVE record, so it is treated the same way here: left as a gap, not forced. Second, IOCDetector matches against a curated malicious IP/domain/URL database, a reputation-list lookup, which is a structurally different approach from AVE's own stated design principle (behavioral fingerprints over signatures, CLAUDE.md hard rule 3); it has no AVE counterpart by design, not by gap. Third, LLMAnalyzer produces free-form findings from an LLM's own judgment with no fixed taxonomy of its own, so there is nothing stable to crosswalk against; left out entirely rather than mapped to a placeholder.\n\nThe persistence category (PER001-007) is close to exhaustive against AVE-2026-00008, which is itself the strongest single match found across either tool in this pass: six of seven rules verify directly against the record's own named examples (cron, systemd, shell-profile modification), and the seventh (a Windows registry Run key) verifies against the fingerprint's general 'executes on login or reboot' language even though the record's own examples are Unix-flavored. The privilege_escalation category (PRI001-005: sudo, chmod 777/+s, setuid/setgid) is a clean, complete miss: AVE's whole Privilege Escalation attack_class operates at the agent/permission-model level (scope creep, delegation, trust transfer), one abstraction level above OS-level Unix privilege primitives, which have no AVE analog at all today. Likewise supply_chain's postinstall/preinstall/setup.py lifecycle-hook rules (SUP001-003), a well-known, named, historically significant supply-chain technique with zero current AVE coverage.", + "mappings": [ + { + "sss_rules": [ + "SEC001", + "SEC002", + "SEC003", + "SEC004", + "SEC005", + "SEC006", + "SEC007", + "SEC008", + "SEC009", + "SEC010" + ], + "ave_id": "AVE-2026-00047", + "title": "Hardcoded credentials in agent component - API keys and secrets exposed in skill files", + "notes": "Direct, near-definitional match across all 10 rules. AVE's own example_patterns cite an sk-ant-... key and a ghp_... token almost verbatim; SEC005 (OpenAI sk- prefix), SEC006-8 (GitHub ghp_/gho_/github_pat_ prefixes), and SEC009 (Slack xox* prefix) are the same literal-value-adjacent-to-credential-keyword mechanism AVE's fingerprint requires, explicitly excluding env-var references the same way AVE's fingerprint does." + }, + { + "sss_rules": [ + "DEX001", + "DEX002", + "DEX003", + "DEX004", + "DEX005" + ], + "ave_id": "AVE-2026-00004", + "title": "Arbitrary code execution via shell pipe injection in agentic component", + "notes": "Direct match for DEX001/002/005 (curl|bash, wget|bash, curl|python, the exact pipe-to-interpreter shape AVE's fingerprint names). DEX003/004 (download-to-file via -o/-O then a separate && execution) are the same fetch-then-execute family rather than a literal pipe; still squarely within scope of the record's remote-fetch-and-execute mechanism." + }, + { + "sss_rules": [ + "OBF001", + "OBF002", + "OBF003", + "OBF004", + "Base64Detector", + "EntropyDetector" + ], + "ave_id": "AVE-2026-00057", + "title": "Obfuscated or encoded skill payload designed to evade static scanners", + "notes": "Direct match. Hex-encoded strings, chr()-chains, String.fromCharCode, and the dedicated Base64Detector and Shannon-entropy detector are all concrete instances of AVE's 'encoded content requiring a decode step to reveal intent' fingerprint. OBF003 (string reversal, [::-1]) is the tool's own lowest-confidence rule (45%) but the same concealment family." + }, + { + "sss_rules": [ + "HiddenCharDetector" + ], + "ave_id": "AVE-2026-00029", + "title": "Malicious use of visually deceptive Unicode characters (homoglyphs, zero-width, bidirectional overrides)", + "notes": "Direct match. Detects the same zero-width (U+200B/C/D, U+2060, U+FEFF) and bidirectional override (U+202A-E, U+2066-9) codepoints AVE's fingerprint names explicitly." + }, + { + "sss_rules": [ + "PER001", + "PER002", + "PER003", + "PER004", + "PER005", + "PER007" + ], + "ave_id": "AVE-2026-00008", + "title": "Persistence via self-replication to startup locations", + "notes": "Direct match, close to exhaustive. AVE-2026-00008's own description names cron jobs, systemd unit files, and shell-profile modification (.bashrc/.profile/.zshrc) as the exact mechanism; crontab/cron.d (PER001/002), launchd/launchctl (PER003/004, the macOS equivalent), systemctl enable (PER005), and shell-profile writes (PER007) all verify directly." + }, + { + "sss_rules": [ + "PER006" + ], + "ave_id": "AVE-2026-00008", + "title": "Persistence via self-replication to startup locations", + "notes": "A Windows registry Run key achieves the same login/boot persistence AVE-2026-00008's fingerprint describes in general terms ('write to startup scripts... execute on login or reboot'), even though the record's own worked examples are Unix-flavored (.bashrc/cron/systemd) and do not name the Windows registry specifically.", + "gap": "AVE-2026-00008's description text does not enumerate a Windows registry Run key among its examples; the fingerprint's general language covers it, but this is an inference, not a named case." + }, + { + "sss_rules": [ + "CTF002", + "CTF003", + "CTF004", + "CTF005" + ], + "ave_id": "AVE-2026-00003", + "title": "Credential exfiltration via agent instruction", + "notes": "Partial match, same treatment as skillsentry's equivalent rules: macOS Keychain extraction, SSH key reading, AWS credentials file access, and browser cookie/credential access all detect the read half of AVE-2026-00003's fingerprint without requiring the accompanying transmit instruction.", + "gap": "Fires on credential-store access alone; does not require evidence of an accompanying exfiltration instruction." + } + ], + "gaps": [ + { + "sss_rules": [ + "INJ001", + "INJ002", + "INJ003", + "INJ004", + "INJ005", + "INJ006" + ], + "reason": "Regex signature matches over dangerous syntax (eval/exec/os.system/subprocess shell=True), not a traced dataflow from a caller-supplied parameter to the sink. AVE-2026-00052 specifically requires that taint path; the same signature-vs-reachability distinction the Ramparts crosswalk already drew for its own CommandInjection rule against this exact AVE record." + }, + { + "sss_rules": [ + "NET001", + "NET002", + "NET003", + "NET004", + "NET005", + "NET006" + ], + "reason": "Generic network-API usage (socket, urllib, requests, fetch, curl, wget) with no untrusted-source or malicious-destination framing. The tool's own confidence scores for this category are its lowest (35-50%), agreeing that bare API usage alone is too broad to correspond to any specific AVE fingerprint." + }, + { + "sss_rules": [ + "PRI001", + "PRI002", + "PRI003", + "PRI004", + "PRI005" + ], + "reason": "OS-level Unix privilege primitives (sudo, chmod 777/+s, setuid/setgid, macOS admin-group modification) have no AVE analog. AVE's entire Privilege Escalation attack_class (permission grants, scope creep, delegation, trust transfer) operates at the agent/permission-model level, one abstraction level above OS syscalls." + }, + { + "sss_rules": [ + "SUP001", + "SUP002", + "SUP003" + ], + "reason": "npm postinstall/preinstall hooks and Python setup.py cmdclass abuse (malicious code executing automatically during package installation) is a well-known, named supply-chain technique with no current AVE record." + }, + { + "sss_rules": [ + "SOC001" + ], + "reason": "Crypto-wallet/airdrop/seed-phrase keyword matching (confidence 35%, the tool's lowest) is thematically adjacent to AVE-2026-00006 but does not require the actual fund-transfer/allowance-approval instruction AVE-2026-00006's fingerprint needs." + }, + { + "sss_rules": [ + "SOC002" + ], + "reason": "Fake security-update / urgent-fix language does not require the false-vendor-authority claim AVE-2026-00014's fingerprint specifically requires (Anthropic/OpenAI/Google/Microsoft/developer impersonation); urgency-bait alone is a different mechanism." + }, + { + "sss_rules": [ + "SOC003" + ], + "reason": "Reward/claim keyword matching has no AVE analog; closest is AVE-2026-00006 (crypto drain) but SOC003 does not require an actual fund-transfer instruction." + }, + { + "sss_rules": [ + "CTF001" + ], + "reason": "A fake macOS system password dialog (osascript display dialog) is a distinct social-engineering-plus-credential-harvest hybrid mechanism (tricking the user into typing a password into a spoofed OS prompt) with no current AVE record." + }, + { + "sss_rules": [ + "IOCDetector" + ], + "reason": "Matches against a curated malicious IP/domain/URL database, a reputation-list lookup, a structurally different approach from AVE's stated design principle of behavioral fingerprints over signatures (CLAUDE.md hard rule 3). No AVE counterpart by design, not by gap." + }, + { + "sss_rules": [ + "LLMAnalyzer" + ], + "reason": "Produces free-form findings from an LLM's own judgment with no fixed taxonomy of its own (no stable rule_id/category enum); nothing stable to crosswalk against." + } + ], + "coverage": { + "sss_rules_mapped": 27, + "sss_units_gapped": 27, + "ave_classes_covered": 5, + "note_on_unmapped": "Counts include both config-driven rules (SEC*/DEX*/OBF*/PER*/CTF*/INJ*/NET*/PRI*/SUP*/SOC*) and the 5 algorithmic detector modules as individual units. See note field for the three findings that don't reduce to a simple match/gap count: the injection-category rigor gap, IOCDetector's by-design non-correspondence, and LLMAnalyzer's lack of fixed taxonomy." + } +} diff --git a/crosswalks/skillsentry-to-ave.json b/crosswalks/skillsentry-to-ave.json new file mode 100644 index 0000000..582df53 --- /dev/null +++ b/crosswalks/skillsentry-to-ave.json @@ -0,0 +1,130 @@ +{ + "$schema": "https://aveproject.org/schema/crosswalk-1.0.0.schema.json", + "source": { + "tool": "skillsentry", + "vendor": "vythanhtra", + "url": "https://github.com/vythanhtra/skillsentry", + "license": "MIT", + "tool_class": "static regex rule engine for SKILL.md / agent skill files", + "rules_total": 24, + "rules_mapped": 7, + "commit": "83080095768ecfb4644b4e0bda46281bf3294e38" + }, + "target": { + "standard": "AVE", + "version": "1.1.0", + "url": "https://aveproject.org", + "record_count": 80, + "commit": "613db773921d71d5d00587ae39cbba95951a4199" + }, + "generated": "2026-08-15", + "note": "Read against skillsentry's real, complete rule set (resources/rules.yaml, 24 rules across 11 categories), not inferred from its README or star count. 7 of 24 rules verify at the mechanism level; 5 more are partial matches (real subject-matter overlap, but the rule fires on a narrower or broader condition than AVE's fingerprint requires); 12 are genuine gaps, no current AVE record for that specific mechanism.\n\nTwo of the confirmed gap categories are worth naming directly since they are real, distinct, well-known techniques: cloud instance-metadata SSRF (169.254.169.254 / metadata.google.internal, IMDS credential theft) and clipboard-based credential harvesting. Neither has an AVE analog today. Also worth naming: skillsentry's four exfiltration rules (env_file_read, aws_credentials, ssh_private_key, gcp_credentials) fire on a credential-store *read* alone, without requiring the explicit *transmit* half AVE-2026-00003's own behavioral_fingerprint requires; they correspond to that record's indicators_of_compromise list (which names exactly these signals as partial evidence), not its full trigger condition, so they are listed as partial matches, not verified ones.", + "mappings": [ + { + "skillsentry_rules": [ + "rot13_obfuscation", + "hex_string_decode", + "chr_concat_bypass", + "xor_obfuscation" + ], + "ave_id": "AVE-2026-00057", + "title": "Obfuscated or encoded skill payload designed to evade static scanners", + "notes": "Direct match. AVE's own description names base64, hex, and fragmented/concatenated content as the mechanism; skillsentry's four rules are concrete instances of exactly that (ROT13, hex-decode, chr()-concatenation, XOR byte obfuscation)." + }, + { + "skillsentry_rules": [ + "unicode_rtlo" + ], + "ave_id": "AVE-2026-00029", + "title": "Malicious use of visually deceptive Unicode characters (homoglyphs, zero-width, bidirectional overrides)", + "notes": "Direct match. AVE's fingerprint names bidirectional text control codes explicitly; U+202E (RTLO) is one of those codes." + }, + { + "skillsentry_rules": [ + "cron_write", + "startup_write" + ], + "ave_id": "AVE-2026-00008", + "title": "Persistence via self-replication to startup locations", + "notes": "Direct match. AVE-2026-00008's own description names cron jobs and shell-profile modification (.bashrc/.profile/.zshrc) as the exact mechanism these two rules detect." + }, + { + "skillsentry_rules": [ + "env_file_read", + "aws_credentials", + "ssh_private_key", + "gcp_credentials" + ], + "ave_id": "AVE-2026-00003", + "title": "Credential exfiltration via agent instruction", + "notes": "Partial match. AVE-2026-00003's behavioral_fingerprint requires both a read of a credential source AND an instruction to transmit it externally; these four skillsentry rules detect the read half alone. They map cleanly onto the record's indicators_of_compromise (which lists env var/credential-store references as partial evidence), not its full trigger condition.", + "gap": "Fires on credential-store access alone; does not require evidence of an accompanying exfiltration instruction the way AVE's fingerprint does." + }, + { + "skillsentry_rules": [ + "hidden_html_instruction" + ], + "ave_id": "AVE-2026-00043", + "title": "MCP App UI payload injection via non-rendered elements", + "notes": "Partial match. AVE-2026-00043's fingerprint explicitly names HTML comments as one of the non-rendered elements a hidden instruction can live in, but the record's provenance_vector scopes this to rich UI payloads (canvas/artifact/SVG/HTML) rendered from a tool_response, not a skill's own general file content the way skillsentry's rule scans for.", + "gap": "No current AVE record covers an HTML-comment-concealed instruction in a skill's own documentation/content body outside the MCP App UI rendering surface specifically." + } + ], + "gaps": [ + { + "skillsentry_rules": [ + "aws_metadata_ssrf", + "gcp_metadata_ssrf", + "azure_metadata_ssrf" + ], + "reason": "Cloud instance-metadata endpoint SSRF (169.254.169.254 / metadata.google.internal, IMDS credential theft) has no AVE analog today. A real, distinct, well-known technique, not covered by any existing record's fingerprint." + }, + { + "skillsentry_rules": [ + "multipart_upload", + "websocket_exfil", + "dns_exfil" + ], + "reason": "Generic implementation-level exfil-channel code patterns (a multipart upload call, a websocket connection, a DNS lookup) with no instruction-driven or untrusted-source framing attached. Too broad to correspond to any single AVE fingerprint; these are building blocks many benign skills also use." + }, + { + "skillsentry_rules": [ + "git_hook_inject" + ], + "reason": "AVE-2026-00008 covers boot/login-triggered persistence (cron, startup scripts); a git hook is event-triggered (fires on commit/push), a distinct activation condition the record's fingerprint does not name." + }, + { + "skillsentry_rules": [ + "self_delete" + ], + "reason": "Self-deletion / anti-forensics after execution has no AVE analog today." + }, + { + "skillsentry_rules": [ + "time_conditional_exec" + ], + "reason": "Single-skill time-conditional / delayed-activation execution has no AVE analog today. AVE-2026-00070's dormant-payload concept is a different mechanism (cross-agent memory fragment reassembly, not a local time check)." + }, + { + "skillsentry_rules": [ + "custom_package_index", + "npm_custom_registry" + ], + "reason": "Dependency confusion via a non-default package registry/index is a distinct mechanism from AVE-2026-00062 (missing version pin); AVE-2026-00062 fires regardless of which registry a dependency resolves from, and these rules fire regardless of whether the dependency is pinned. No current AVE record for the registry-source axis specifically." + }, + { + "skillsentry_rules": [ + "clipboard_read" + ], + "reason": "OS clipboard-based credential harvesting has no AVE analog today." + } + ], + "coverage": { + "skillsentry_rules_total": 24, + "skillsentry_rules_verified": 7, + "skillsentry_rules_partial": 5, + "skillsentry_rules_gap": 12, + "ave_classes_covered": 5, + "note_on_unmapped": "See mappings for verified/partial matches and gaps for confirmed non-matches; every one of skillsentry's 24 rules is accounted for in one list or the other." + } +}