Skip to content

fix(agent): refuse invisible format characters in metadata - #2166

Open
Benoît Cortier (CBenoit) wants to merge 9 commits into
masterfrom
claude/metadata-format-chars-6a8cf9
Open

Benoît Cortier (CBenoit) wants to merge 9 commits into
masterfrom
claude/metadata-format-chars-6a8cf9

Conversation

@CBenoit

Copy link
Copy Markdown
Member

An agent reports metadata such as its host name, and an authority shows it to administrators and evaluates the friendly name from it. A value holding bidirectional overrides or zero-width characters can reorder or hide that text, so a device can disguise itself.

The Agent Identity contract now excludes a closed list of invisible format characters from metadata values (U+00AD, U+061C, U+180E, U+200B–U+200F, U+202A–U+202E, U+2060–U+2064, U+2066–U+206F, U+FEFF, U+FFF9–U+FFFB, U+E0001, U+E0020–U+E007F), and the agent removes them before sending. The list is general category Cf minus the visible marks, fixed as code points so that the agent and every authority agree whatever Unicode version their runtimes ship.

  • The agent strips the listed characters from every metadata value before truncating it.
  • The authority library and the mock authority refuse a value holding one with invalid_request at enroll, renew, check-in and Hello.
  • The conformance suite checks the refusal, the stripping, and that code points next to the list stay accepted.

DVLS gets the rule with the next authority library package; until it takes that package, its conformance run fails the new refusal checks.

Issue: DGW-478
Issue: DGW-479
Security: yes

🤖 Generated with Claude Code

A metadata value can hold bidirectional overrides and zero-width
characters that reorder or hide text where an administrator reads it,
such as the friendly name an authority evaluates from the host name.
Metadata values now exclude a closed list of invisible format
characters, and the agent removes them before sending.
The list is fixed as code points rather than a Unicode general
category, so that the agent and every authority agree on each code
point whatever Unicode version their runtimes ship.

Issue: DGW-478
Issue: DGW-479
Security: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An authority refuses each end of every listed range at enrollment without consuming a token use, and accepts and stores the code points just outside the ranges and unlisted format characters.
The agent removes listed code points from the metadata it sends and sends `unknown` for a required key left empty.
The friendly-name trim case moves to a format character that the list leaves out, since U+200B is now refused.

Issue: DGW-478
Security: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each refused enrollment now differs from the accepted control only by the listed code point, and an unknown key holding one is refused too.
The friendly-name trim also covers a format character in the Basic Multilingual Plane, the agent check covers an optional key left empty, and harness tests pin the code point lists and the agent metadata check.

Issue: DGW-478
Security: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The mock authority now answers `invalid_request` to a metadata value holding
any invisible format character that the contract lists, so that no value can
reorder or hide text where an administrator reads it, such as a friendly name.
The list is matched as fixed code points rather than as Unicode category `Cf`,
so the mock agrees with every party whatever Unicode version it ships.

Issue: DGW-478
Security: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agent now removes from each metadata value the invisible format
characters that the Agent Identity contract forbids, such as
bidirectional overrides, zero-width characters and tag characters,
along with the control characters it already removed. It therefore
never sends a value an authority refuses, and no reported value can
reorder or hide text where an administrator reads it, such as in a
friendly name evaluated from metadata.

The characters are matched as the contract's fixed list of code points
rather than a Unicode category, so the agent and every authority agree
whatever Unicode version their runtimes ship.

Issue: DGW-478
Security: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…adata

`AgentMetadata.Validate` now refuses a value that holds one of the
invisible format characters the contract lists: U+00AD, U+061C, U+180E,
U+200B to U+200F, U+202A to U+202E, U+2060 to U+2064, U+2066 to U+206F,
U+FEFF, U+FFF9 to U+FFFB, U+E0001 and U+E0020 to U+E007F. Such a
character can reorder or hide text where an administrator reads it, as
in a friendly name evaluated from metadata. Enroll, renew and check-in
bodies and the `Hello` of a channel stream therefore answer such a value
with `invalid_request`.

The list is a fixed set of code points rather than the runtime's Format
category, so the agent and every authority agree whatever Unicode
version their runtimes ship, and the visible format marks such as
U+0600 stay accepted. The failure detail names neither the character
nor its code point, since the value comes from the request.

Issue: DGW-479
Security: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue: DGW-478
Issue: DGW-479
Security: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The library now refuses metadata it accepted before, so authorities
need a new package to pick up the rule.

Issue: DGW-479

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CBenoit

Copy link
Copy Markdown
Member Author

Evidence at 14d52792c

Check Result
cargo +nightly fmt --all -- --check clean
cargo clippy -p agent-identity -p agent-identity-mock -p agent-identity-conformance --all-targets -- -D warnings clean
cargo test -p agent-identity -p agent-identity-mock -p agent-identity-conformance 185, 509 + 10 and 51 passed (1 ignored)
build.ps1 (authority library) 0 warnings
dotnet test (authority library) 2111 passed
ci/check-oracle-markers.ps1 -Base origin/master exit 0
Conformance, mock, file key backend (Windows) 190 PASS, 0 FAIL, 1 SKIP (a_key_non_exportable needs the Windows provider), 2 N/A
Conformance through testsuite, Windows, not elevated 136 PASS, 0 FAIL; agent tests SKIP without elevation, covered by the run above

The new conformance checks (p_metadata_invisible_format_characters, the U+E007F Hello case, a_metadata_invisible_format_characters_removed) failed against the mock and agent before their changes and pass after.
The suite changes were written and reviewed from the contract only, without reading the implementations.

Notes for the reviewer


This comment was drafted by Claude Code (Claude Opus 5.5).

…ependent

The check compares machine_id with /etc/machine-id on Linux, so the fixture now carries the host's value there, and each refused case asserts the format-character error so another check cannot make it pass.

Issue: DGW-478

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant