Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions changelog.d/unreleased/3116.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: security
issues:
- 3116
affected:
- src/CodeIndex/Mcp/McpBoundedText.cs
- src/CodeIndex/Mcp/McpToolHandlers.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP enum-like scalar arguments are bounded before normalization (#3116)** — oversized `format`, `groupBy`, and related scalar option values are rejected before trimming or lowercasing, and diagnostics echo only a bounded display value with truncation metadata.

## 日本語

- **MCP の enum 風 scalar 引数を正規化前に制限するようになりました (#3116)** — `format`、`groupBy` などの scalar option 値が大きすぎる場合は trim / lowercase の前に拒否し、診断には切り詰めた表示値と truncation metadata だけを返します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/3117.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: security
issues:
- 3117
affected:
- src/CodeIndex/Mcp/McpServer.cs
- src/CodeIndex/Mcp/McpToolHandlers.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP unknown argument diagnostics truncate property names (#3117)** — unknown argument names now use bounded display values in errors and audit/telemetry key sketches, with original length metadata when truncation occurs.

## 日本語

- **MCP の未知argument診断でproperty名を切り詰めるようになりました (#3117)** — 未知argument名はエラーおよび audit / telemetry のkey概要でbounded display値を使い、切り詰め時は元の長さmetadataも返します。
19 changes: 19 additions & 0 deletions changelog.d/unreleased/3118.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
category: security
issues:
- 3118
affected:
- src/CodeIndex/Mcp/McpBoundedText.cs
- src/CodeIndex/Mcp/McpServer.cs
- src/CodeIndex/Mcp/McpToolHandlers.cs
- tests/CodeIndex.Tests/McpServerTests.cs
- tests/CodeIndex.Tests/McpAuditLogTests.cs
---

## English

- **MCP unknown tool diagnostics truncate tool names (#3118)** — unknown tool names now use bounded display values in JSON-RPC errors, batch slot results, telemetry, and audit logs, with original length metadata when truncation occurs.

## 日本語

- **MCP の未知tool診断でtool名を切り詰めるようになりました (#3118)** — 未知tool名は JSON-RPC error、batch slot結果、telemetry、audit log で bounded display 値を使い、切り詰め時は元の長さmetadataも返します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/3119.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: security
issues:
- 3119
affected:
- src/CodeIndex/Mcp/McpBoundedText.cs
- src/CodeIndex/Mcp/McpServer.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP unsupported protocol diagnostics truncate requested versions (#3119)** — unsupported `protocolVersion` values are bounded during negotiation before appearing in initialize errors, structured data, or stderr logs, with original length metadata when truncation occurs.

## 日本語

- **MCP の非対応 protocol 診断で要求versionを切り詰めるようになりました (#3119)** — 非対応の `protocolVersion` は交渉時に bounded display 化し、initialize error、structured data、stderr log には切り詰めた値と長さmetadataだけを返します。
20 changes: 20 additions & 0 deletions changelog.d/unreleased/3120.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
category: security
issues:
- 3120
affected:
- src/CodeIndex/Mcp/AuditLogSink.cs
- src/CodeIndex/Mcp/McpBoundedText.cs
- src/CodeIndex/Mcp/McpServer.cs
- src/CodeIndex/Mcp/McpToolHandlers.cs
- tests/CodeIndex.Tests/McpAuditLogTests.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP clientInfo fields are bounded before reuse (#3120)** — `clientInfo.name` and `clientInfo.version` are captured as bounded display values before status output, caller identity, rate-limit diagnostics, caller-swap logs, and audit records reuse them, with truncation metadata where values are shortened.

## 日本語

- **MCP の clientInfo フィールドを再利用前に制限するようになりました (#3120)** — `clientInfo.name` と `clientInfo.version` は status 出力、caller identity、rate-limit 診断、caller-swap log、audit record で再利用する前に bounded display 化し、切り詰め時は metadata も出力します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/3121.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: security
issues:
- 3121
affected:
- src/CodeIndex/Mcp/McpBoundedText.cs
- src/CodeIndex/Mcp/McpServer.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP prompt names and arguments are bounded before prompt generation (#3121)** — `prompts/get` now rejects oversized prompt names or argument strings before embedding them in prompt text or diagnostics, and errors return bounded display values with truncation metadata.

## 日本語

- **MCP prompt の name と argument を生成前に制限するようになりました (#3121)** — `prompts/get` は巨大な prompt name や argument 文字列を prompt text / 診断へ埋め込む前に拒否し、エラーには bounded display 値と truncation metadata を返します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/3122.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: security
issues:
- 3122
affected:
- src/CodeIndex/Mcp/McpBoundedText.cs
- src/CodeIndex/Mcp/McpServer.cs
- tests/CodeIndex.Tests/McpServerTests.cs
---

## English

- **MCP resources/read caps resource URIs before parsing (#3122)** — `resources/read` now rejects oversized URIs before URI parsing or unescaping and echoes bounded URI display values in invalid and not-found diagnostics.

## 日本語

- **MCP resources/read が URI parse 前に長さ制限するようになりました (#3122)** — `resources/read` は巨大 URI を URI parse / unescape 前に拒否し、invalid / not-found 診断には bounded URI display 値を返します。
31 changes: 30 additions & 1 deletion src/CodeIndex/Mcp/AuditLogSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,22 @@ internal static string SerializeEvent(AuditEvent evt, bool includeValues)
jw.WriteStartObject();
jw.WriteString("timestamp", evt.Timestamp.ToString("O", CultureInfo.InvariantCulture));
jw.WriteString("tool", evt.Tool);
if (evt.ToolLength is { } toolLength)
jw.WriteNumber("tool_length", toolLength);
if (evt.ToolTruncated)
jw.WriteBoolean("tool_truncated", true);
if (evt.CallerName is { } caller)
jw.WriteString("caller", caller);
if (evt.CallerNameLength is { } callerLength)
jw.WriteNumber("caller_length", callerLength);
if (evt.CallerNameTruncated)
jw.WriteBoolean("caller_truncated", true);
if (evt.CallerVersion is { } callerVersion)
jw.WriteString("caller_version", callerVersion);
if (evt.CallerVersionLength is { } callerVersionLength)
jw.WriteNumber("caller_version_length", callerVersionLength);
if (evt.CallerVersionTruncated)
jw.WriteBoolean("caller_version_truncated", true);
if (evt.RequestId is { } reqId)
jw.WriteString("request_id", reqId);

Expand All @@ -231,6 +243,16 @@ internal static string SerializeEvent(AuditEvent evt, bool includeValues)
jw.WriteNumber(kv.Key, kv.Value);
jw.WriteEndObject();

if (evt.ArgKeyLengths is { Count: > 0 } argKeyLengths)
{
jw.WritePropertyName("arg_key_lengths");
jw.WriteStartObject();
foreach (var kv in argKeyLengths)
jw.WriteNumber(kv.Key, kv.Value);
jw.WriteEndObject();
jw.WriteBoolean("arg_keys_truncated", true);
}

if (includeValues && evt.ArgValues is { } values)
{
jw.WritePropertyName("arg_values");
Expand Down Expand Up @@ -278,5 +300,12 @@ internal sealed record AuditEvent(
int? ResultCount,
double ElapsedMs,
int ErrorCode,
string? ErrorType);
string? ErrorType,
int? ToolLength = null,
bool ToolTruncated = false,
IReadOnlyList<KeyValuePair<string, int>>? ArgKeyLengths = null,
int? CallerNameLength = null,
bool CallerNameTruncated = false,
int? CallerVersionLength = null,
bool CallerVersionTruncated = false);
}
48 changes: 48 additions & 0 deletions src/CodeIndex/Mcp/McpBoundedText.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Text;
using System.Text.Json.Nodes;

namespace CodeIndex.Mcp;

internal readonly record struct BoundedMcpText(string Text, int OriginalLength, bool Truncated)
{
internal void AddMetadata(JsonObject target, string prefix)
{
if (!Truncated)
return;

target[$"{prefix}_length"] = OriginalLength;
target[$"{prefix}_truncated"] = true;
}
}

internal static class McpBoundedText
{
internal const int MaxScalarArgumentChars = 512;
internal const int MaxDiagnosticDisplayChars = 128;
internal const int MaxToolNameChars = 128;
internal const int MaxProtocolVersionChars = 128;
internal const int MaxClientInfoChars = 128;
internal const int MaxClientIdentityChars = (MaxClientInfoChars * 2) + 1;
internal const int MaxPromptNameChars = 128;
internal const int MaxPromptArgumentChars = 512;
internal const int MaxResourceUriChars = 4096;

internal static BoundedMcpText ForDisplay(string value, int maxChars = MaxDiagnosticDisplayChars)
{
ArgumentNullException.ThrowIfNull(value);
ArgumentOutOfRangeException.ThrowIfNegative(maxChars);

var truncated = value.Length > maxChars;
var displayLength = Math.Min(value.Length, maxChars);
var sb = new StringBuilder(displayLength + (truncated ? 3 : 0));
for (var i = 0; i < displayLength; i++)
{
var ch = value[i];
sb.Append(ch < 0x20 || ch == 0x7F ? '?' : ch);
}
if (truncated)
sb.Append("...");

return new BoundedMcpText(sb.ToString(), value.Length, truncated);
}
}
Loading
Loading