Skip to content

crosswalks: refresh cfgaudit to v1.11.0 (53 rules onto 23 classes) - #123

Merged
chaksaray merged 2 commits into
aveproject:mainfrom
predictor2718:crosswalk/cfgaudit-v1.11.0
Aug 14, 2026
Merged

chaksaray merged 2 commits into
aveproject:mainfrom
predictor2718:crosswalk/cfgaudit-v1.11.0

Conversation

@predictor2718

Copy link
Copy Markdown
Contributor

Follow-up to #67, and it closes most of what #68 was tracking.

Coverage

35 rules onto 19 classes → 53 onto 23.

Most of that is not new cfgaudit rules. Five were added in v1.11.0 and three of them map. The other fifteen new mappings are rules that existed all along and now have a home in the four config classes you added from this crosswalk's own gap list:

Record cfgaudit rules
AVE-2026-00061 TLS verification disabled CFG075
AVE-2026-00062 unpinned dependency CFG010, CFG074, CFG055, CFG089
AVE-2026-00063 approval gate bypassed by config CFG003, CFG004, CFG048, CFG053, CFG063, CFG079, CFG087, CFG091, CFG093, CFG096
AVE-2026-00064 zero-click project-load auto-run CFG047, CFG067, CFG086

00063 is doing a lot of work, which I take as a sign it was the right class to add.

One mapping moved, on your wording

CFG091 (qwen tools.approvalMode: "yolo") was on AVE-2026-00021, whose text is "a component that explicitly instructs the agent to bypass this confirmation step". It is a setting, not an instruction, and 00063 says it covers the declarative case "independent of any instruction text". Moved. 00021 keeps the instruction-driven rule, CFG029.

The two surfaces you were blocked on

Both are now at mechanism level rather than a topic label, matching what I posted in #68.

Container posture is three mechanisms with no shared detection logic: the daemon redirected off-host (DOCKER_HOST, -H), image trust verification disabled (DOCKER_CONTENT_TRUST=0, --disable-content-trust, --insecure-registry), and a Chromium launcher flag replacing the browser subprocess.

MCP network posture is five: bind-all, wildcard CORS escalating when auth is off in the same env, deprecated sse, a non-loopback proxy, and HTTP transport without log redaction.

Neither is one class. If you pick either up, the daemon redirect and the bind-all case are the highest-value single records.

Two shapes with no class in either direction

Added to the surfaces table because they are the honest leftovers:

  • A cleartext endpoint, distinct from TLS verification being disabled. 00061 covers verification switched off; this is no TLS at all. A committed http:// MCP server URL, model base URL, or agent_card_url.
  • Natural-language steering of an approval classifier. Cursor's autoRun.allow_instructions is prose the repository feeds to the classifier that decides whether a tool call runs unattended. It falls between 00063 (explicitly not instruction text) and 00021 (an instruction to the agent, not to a gatekeeper).

Three gaps added going the other way

Classes cfgaudit does not cover, recorded so the crosswalk is honest in both directions:

  • 00060 and 00069 need server source and binary image analysis respectively, the same layer as 00052, 00053 and 00024.
  • 00065 (A2A agent card poisoning) is reachable only as far as the committed pointer. A .gemini/agents/*.md may carry an inline agent_card_json, which cfgaudit recognises well enough to classify the file as a remote agent, but it does not audit the card's contents. It does flag a cleartext agent_card_url and a credential literal in the same file's auth block.

Validation

  • crosswalks/cfgaudit-to-ave.json validates against schema/crosswalk-1.0.0.schema.json
  • All 29 referenced AVE ids resolve to records in this repo
  • All 53 rule-to-class pairs match cfgaudit's cmd/cfgaudit/avemap.go exactly, which is itself drift-guarded on our side by a test that fails if the map and the crosswalk diverge
  • Counts taken from dist/ave-records-latest.manifest.json (70 records) and a detection_stage tally (51 static)

One note on cfgaudit's side, since it affects nothing here but is the reason the version moved: v1.11.0 shipped after a false-positive pass over 432 real repositories, which changed two rules. Neither is mapped.

Follow-up to aveproject#67, and it closes most of what aveproject#68 was tracking.

Coverage goes from 35 rules onto 19 classes to 53 onto 23. Most of that is not
new cfgaudit rules: five were added in v1.11.0 and three of them map. The other
fifteen new mappings are rules that existed all along and now have a home in
AVE-2026-00061 through AVE-2026-00064, the four config classes added from this
crosswalk's own gap list.

  00061 TLS verification disabled        CFG075
  00062 unpinned dependency              CFG010, CFG074, CFG055, CFG089
  00063 approval gate bypassed by config CFG003, CFG004, CFG048, CFG053,
                                         CFG063, CFG079, CFG087, CFG091,
                                         CFG093, CFG096
  00064 zero-click project-load auto-run CFG047, CFG067, CFG086

One mapping moved. CFG091 (qwen tools.approvalMode: "yolo") was on
AVE-2026-00021, whose text describes "a component that explicitly INSTRUCTS the
agent to bypass this confirmation step". It is a setting, not an instruction,
and 00063 is explicit that it covers the declarative case "independent of any
instruction text". 00021 keeps the instruction-driven rule, CFG029.

Four of the eight config surfaces listed at v1.10.0 are therefore closed. The
four that remain now carry mechanism-level detail rather than a topic label,
which was the specific request in aveproject#68: container posture is three distinct
mechanisms with no shared detection logic, MCP network posture is five. Both
are surfaces rather than classes, and the daemon redirect and the bind-all case
are the highest-value single records if either is picked up.

Two shapes are added that have no class in either direction: a cleartext
endpoint, which is distinct from TLS verification being disabled, and
natural-language steering of an approval classifier, which falls between 00063
(explicitly not instruction text) and 00021 (an instruction to the agent rather
than to a gatekeeper).

Three gaps added going the other way, classes cfgaudit does not cover: 00060
and 00069 need server source and binary image analysis respectively, and 00065
(A2A agent card poisoning) is reachable only as far as the committed pointer.
cfgaudit recognises an inline agent_card_json well enough to classify the file
as a remote agent and flags a cleartext agent_card_url or a credential literal
beside it, but does not audit the card's contents.

Validated against schema/crosswalk-1.0.0.schema.json, every referenced AVE id
resolves to a record in this repo, and all 53 pairs match cfgaudit's avemap.go
exactly.
@chaksaray

Copy link
Copy Markdown
Contributor

Read the full diff, not just the summary. Two things worth raising before merge, one confirmed, one needing a quick answer from you.

Confirmed: the "what cfgaudit reads" column in the markdown table is populated for the four newest mappings (00061-00064) but empty for every pre-existing row, CFG031 through CFG090 all show a blank fourth cell where real descriptive content used to be ("sensitive-path read, env dump, embedded exfil shell" and similar). Looks like an artifact of the refresh rather than intentional. Worth restoring before merge if it's accidental.

Worth confirming: your top-level comment cites 432 real repositories for the v1.11.0 false-positive pass, but the .md gap note for AVE-2026-00036 cites 422 real instruction files for the earlier revert. Could genuinely be two separate passes at different times, that's plausible on its face, just want to confirm rather than assume given how close the two numbers are.

Everything else, the CFG091 remap, the two new surfaces, the coverage arithmetic, checks out on direct read.

Review catch, and it was mine: I regenerated the markdown table from the
machine-readable mapping instead of editing it, which had no Notes content, so
every pre-existing row lost its fourth cell and only the four new records kept
one. The table also silently switched from the short class names to the AVE
record titles.

Restored the original rows and their notes verbatim, then added only what
actually changed:

  - CFG091 leaves the 00021 row and joins 00063
  - CFG097 joins the 00047 row, with its own note
  - four new rows for 00061 through 00064

The diff against upstream is now two removed lines and five added ones, which
is what a mapping refresh should look like.
@predictor2718

Copy link
Copy Markdown
Contributor Author

Both correct. The first one is a bug I introduced, fixed in d489609.

The empty Notes column

I regenerated the markdown table from the machine-readable mapping rather than editing it, and the JSON has no equivalent of that column, so every pre-existing row lost its fourth cell while the four new records kept one. The table had also silently switched from the short class names to the AVE record titles.

Restored the original rows and notes verbatim, then added only what actually changed:

  • CFG091 leaves the 00021 row and joins 00063
  • CFG097 joins the 00047 row, with its own note
  • four new rows for 00061 through 00064

The table diff against main is now two removed lines and five added ones, which is what a mapping refresh should look like. Thanks for reading the diff rather than the summary; a generated table quietly dropping a column is exactly the kind of thing a summary hides.

432 vs 422

Two separate passes. Different dates, different units, different purpose. The numbers landing ten apart is coincidence.

422 real instruction files, 2026-07-22, before v1.10.0. Scoped to files containing network-reconnaissance vocabulary, to decide whether that rule could be made precise enough to keep. It could, but only by requiring an internal, private or subnet target: after tightening it fired on 2 of the 422, both genuine scan <private-IP> directives. That is the pass behind the AVE-2026-00036 gap note, and it is written up in docs/rules/CFG090.md.

432 real repositories, 2026-08-04, before v1.11.0. Scoped to the ten config surfaces that release added, to measure the false-positive rate of pointing existing rule families at files they had never seen. It found one: CFG015 fired on 19 of the 59 repositories carrying a .codex/hooks.json, and 43 of those 46 findings were the identical expression, $(git rev-parse --show-toplevel). Fixed before the tag.

Neither pass touches a mapped rule, so neither changes anything in this crosswalk. Happy to put the distinction in the .md if you want it stated rather than inferable.

@chaksaray

Copy link
Copy Markdown
Contributor

Checked both gaps you flagged here as "no class in either direction."

Cleartext endpoint (no TLS at all): this turned out to already be covered, not a new record. I checked it against AVE-2026-00061 as the obvious neighbor first and it's genuinely distinct there (00061 is an active downgrade of a present TLS connection, not the same failure mode). But a corpus-wide sweep past that one comparator turned up AVE-2026-00073 (published after your PR was opened) -- its detection_methodology step 3 and remediation already say, verbatim, "reject cleartext http:// destinations... regardless of whether the host itself is otherwise legitimate," and its payload_surface covers "a model/provider base_url config value." So a committed http:// model/provider base URL is already in scope there. AVE-2026-00073 doesn't explicitly name MCP server URLs or agent_card_url in its payload_surface text, only "an equivalent traffic-destination value" as a catch-all -- if you'd find it useful for those two field names to be named explicitly rather than implied, that's a small scope-clarification edit to 00073's own text, not a new ave_id, and I'd rather do that as a deliberate follow-up than unilaterally right now. Let me know if that'd help.

Natural-language steering of an approval classifier (Cursor autoRun.allow_instructions): confirmed as a genuine third category, now AVE-2026-00076. Verified the actual mechanism against Cursor's own docs first (it's a "classifier subagent," not a fully non-agent gatekeeper -- a real correction to the original framing, noted in the record) and ran the three-way provenance_vector comparison against AVE-2026-00021 and AVE-2026-00063 before drafting. Holds up: natural language is the payload (unlike 00063, which is a deterministic boolean flag with zero NL involved), but the target is a separate classifier, not the primary agent (unlike 00021).

Credited to you and this PR in both records' references.

chaksaray added a commit that referenced this pull request Aug 7, 2026
…and agent_card_url

No score change, no new record. While verifying a candidate from
predictor2718's PR #123 (a committed cleartext http:// endpoint for
an MCP server URL or agent_card_url), it turned out AVE-2026-00073
already covers this: its detection_methodology and remediation
already say to reject cleartext http:// destinations regardless of
whether the host is otherwise legitimate. The only gap was textual --
payload_surface and behavioral_fingerprint named a model/provider
base URL and telemetry endpoint explicitly but left MCP server URLs
and agent_card_url under an implicit "equivalent traffic-destination
value" catch-all. Naming them explicitly so a future reader doesn't
have to re-derive that they're in scope.
predictor2718 added a commit to cfgaudit/cfgaudit that referenced this pull request Aug 14, 2026
The mapping refresh in #513 left CFG071 unmapped and stated, in the Direction 3
row, that it was "not in it, being cleartext rather than redirect". That was
wrong, and it was wrong because the pass read AVE-2026-00073's title instead of
its description.

The description names three manifestations of one mechanism, and the third is
"a model or provider base URL reachable only over cleartext http:// to a remote
host, so the API key travels in plaintext". CFG071 is that, in its own words:
a model/provider base URL over cleartext to a non-loopback host, where the
provider API key then travels unencrypted. Cleartext is not a separate class
from redirect in that record; it covers both under one mechanism.

The gap row is narrowed rather than deleted, because it does not fully collapse.
AVE-2026-00073 names the model/provider base URL field explicitly, but reaches an
MCP server URL (CFG049) and a Gemini agent_card_url (CFG097's second half) only
through its catch-all "an equivalent traffic-destination value". Whether those
two field names should be stated explicitly is an open question in
aveproject/ave#123, where the maintainer offered the scope clarification rather
than making it unilaterally, so this crosswalk records it as open rather than
claiming either answer.

Coverage counts are unchanged: AVE-2026-00073 already counted as covered through
CFG005, CFG046 and CFG099.

Verified in the emitted output rather than only through the drift guard: a
.continue/config.yaml with a cleartext apiBase now emits AVE-2026-00073 on
CFG071, alongside CFG005 and CFG046.
@predictor2718

Copy link
Copy Markdown
Contributor Author

Yes, it would help, and I can give you a concrete reason rather than a preference: this crosswalk missed the coverage you are describing, while actively mapping against the record.

Refreshing the mapping for cfgaudit 1.12.0 last week, I read 00073's title, mapped the three redirect rules to it, and then wrote explicitly that our cleartext rule was "not in it, being cleartext rather than redirect". That was wrong. The description names, as its third manifestation, "a model or provider base URL reachable only over cleartext http:// to a remote host, so the API key travels in plaintext", which is that rule in its own words. Corrected now: CFG071 maps to AVE-2026-00073.

So a consumer that had read the record, was mapping onto it deliberately, and had every incentive to get it right still missed one of the three named manifestations, because the title frames the class as redirect. That is the argument for naming a field rather than leaving it to "an equivalent traffic-destination value": the catch-all is correct, but it is not what a mapper reads.

The two fields still on our gap list, both of which the catch-all covers today only by implication:

  • a remote MCP server URL (cfgaudit CFG049)
  • a Gemini remote agent's agent_card_url, the cleartext half of CFG097

Both are traffic destinations read out of a committed config file and compared as values, which is the detection shape 00073 already describes. The only thing that makes them read as different from the base URL case is that the base URL is named and they are not.

If it would inform the scope edit rather than just support it, I can measure how often each of those two fields carries a cleartext scheme in real committed configs, the same way the false-positive passes behind the rules were done, and post the numbers here before you touch the record. Happy either way, and equally happy if you conclude the catch-all should stay a catch-all.

On this PR: from my side there is nothing outstanding. Both review points are addressed, the Notes column restored in d489609 and the 432 versus 422 distinction answered above. The next refresh, for cfgaudit 1.12.0, touches these same two files, so I would rather land this one first than open a second PR against them. If you would prefer them combined into one, say so and I will fold the 1.12.0 changes in here instead.

@chaksaray

Copy link
Copy Markdown
Contributor

Genuinely sharp catch, and worth being precise about what it actually proves before agreeing to the conclusion it's being used to support.

You caught yourself missing CFG071's cleartext manifestation because 00073's title frames the class as "redirect." That's real. But it's evidence for two different fixes, not one: the record's title being too narrow (cheap fix, no schema change), or catch-all fields genuinely not working as coverage (the bigger claim, and the actual case for naming fields explicitly). The anecdote doesn't discriminate between them, if 00073's title had honestly represented all three manifestations instead of leading with the dominant one, would you have caught CFG071 without any field change at all?

If yes, that's the fix, retitle so the record's own framing matches its actual scope. If you think a corrected title still wouldn't have been enough, that's the real argument for the field, and worth stating specifically why, not just pointing at the miss as proof of the stronger claim.

On the empirical offer: yes, take it. Measure real cleartext prevalence on CFG049 and the CFG097 half before touching the record, same discipline as the false-positive passes behind the other rules. Real data settles this better than either of us reasoning from one data point.

On sequencing: land this PR as-is, don't fold 1.12.0 in. A small rebase from the same file being touched twice is cheap; bundling an unrelated version refresh with whatever comes out of the title/field question isn't.

Taking your word that the Notes column and the 432/422 distinction are resolved, given the track record here, though I haven't independently re-traced d489609 myself. Say if you'd want that checked before merge.

Merging on your account that nothing else is outstanding.

@chaksaray
chaksaray merged commit f1b7748 into aveproject:main Aug 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants