anthropics / anthropics/anthropic-sdk-csharp

Path parameters are interpolated into request URLs without percent-encoding or dot-segment rejection

Offen
#248 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
C#
Sterne
322
Forks
105
Ø Merge
1 T. 6 Std.
Gemergte PRs (30 T.)
9

Beschreibung

## What

Generated `*Params` classes build their URL by interpolating the path parameter directly, with no percent-encoding and no dot-segment check. Example, `src/Anthropic/Models/Beta/Vaults/Credentials/CredentialRetrieveParams.cs:135`:

```csharp
public override Uri Url(ClientOptions options)
{
var queryString = this.QueryString(options);
return new UriBuilder(
options.BaseUrl.ToString().TrimEnd('/')
+ string.Format("/v1/vaults/{0}/credentials/{1}", this.VaultID, this.CredentialID)
)
{
Query = string.IsNullOrEmpty(queryString) ? "beta=true" : ("beta=true&" + queryString),
}.Uri;
}
```

`System.UriBuilder` canonicalises per RFC 3986, so a `../` in the value silently changes which endpoint the request reaches.

106 parameter classes are affected. Note that a same-line search undercounts: `rg -l 'string\.Format\("/v1/'` returns 91, while `rg -l -U 'string\.Format\(\s*"/v1/'` returns 106, because 15 classes put the format string on the next line (e.g. `MemoryRetrieveParams.cs:158`, `CertificateRetrieveParams.cs:139`). None of the 106 calls any encoder.

## Reproduction

```csharp
var p = new CredentialRetrieveParams {
VaultID = "vault_A",
CredentialID = "../../vault_B/credentials/cred_x"
};
// p.Url(options).AbsolutePath
// actual: /v1/vaults/vault_B/credentials/cred_x
// expected: something under /v1/vaults/vault_A/credentials/
```

Three input forms normalise, which is relevant if an application tries to filter them:

- `../../vault_B/...`
- `%2e%2e/%2e%2e/vault_B/...` (survives a literal `..` denylist)
- `..\..\vault_B\...` (.NET converts backslashes first)

A `#` in the value also truncates a fixed suffix, so at a template like `/v1/files/{0}/content` the request lands on the parent resource instead. Of 64 distinct path templates under `src/Anthropic/Models`, 42 have a fixed suffix after the placeholder (e.g. `/v1/agents/{0}/archive`, `/v1/deployments/{0}/pause`) and 22 end at the placeholder.

`Uri.EscapeDataString` is already used in this repository (12 occurrences, in `Anthropic.Aws/AwsSigner.cs` and `Anthropic.Bedrock/MantleAwsSigner.cs` for SigV4 canonicalisation), just not at these call sites. `SecurityHelpers.ValidateProfileName` (`src/Anthropic/Credentials/SecurityHelpers.cs:41`) also already rejects `..`, `/`, `\` and nulls for credential profile names, so the pattern exists in the codebase.

## Suggested change

A shared helper applied at the generated `Url()` call sites:

1. Percent-encode each path parameter to the RFC 3986 section 3.3 `pchar` set, treating `/` as unsafe.
2. After interpolation, reject any `.` or `..` segment (literal or `%2e`-encoded) remaining in the assembled path.

Since these files are generated, this is presumably a template change rather than 106 edits.

## Test coverage note

`Url()` output is asserted in many `src/Anthropic.Tests/Models/**/*ParamsTest.cs` files, so URL construction is already a tested concern, but every case uses a benign literal such as `TunnelID = "tunnel_id"`. No test exercises `../`, `#`, or `%2e` in a path parameter.

Verified against `da57c281`, `src/Anthropic` 12.42.0, .NET 8 (SDK 8.0.424).

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.