Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit 7da8dea

Browse files
Merging e77dad8 into trunk-temp/pr-4046/7debe020-d8e2-460e-b94c-7d9de448fce2
2 parents b4ec45c + e77dad8 commit 7da8dea

2 files changed

Lines changed: 67 additions & 1 deletion

File tree

packages/agent/src/session-log-writer.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,45 @@ describe("SessionLogWriter", () => {
4747
expect(entries).toHaveLength(2);
4848
});
4949

50+
it("redacts MCP authorization headers before persistence", async () => {
51+
const sessionId = "s1";
52+
logWriter.register(sessionId, { taskId: "t1", runId: sessionId });
53+
54+
logWriter.appendRawLine(
55+
sessionId,
56+
JSON.stringify({
57+
jsonrpc: "2.0",
58+
method: "session/new",
59+
params: {
60+
mcpServers: [
61+
{
62+
name: "posthog",
63+
headers: [
64+
{ name: "Authorization", value: "Bearer protocol-secret" },
65+
{ name: "x-posthog-project-id", value: "123" },
66+
],
67+
},
68+
],
69+
},
70+
}),
71+
);
72+
await logWriter.flush(sessionId);
73+
74+
const entries: StoredNotification[] = mockAppendLog.mock.calls[0][2];
75+
expect(JSON.stringify(entries)).not.toContain("protocol-secret");
76+
expect(entries[0].notification.params).toEqual({
77+
mcpServers: [
78+
{
79+
name: "posthog",
80+
headers: [
81+
{ name: "Authorization", value: "[REDACTED]" },
82+
{ name: "x-posthog-project-id", value: "123" },
83+
],
84+
},
85+
],
86+
});
87+
});
88+
5089
it("ignores unregistered sessions", async () => {
5190
logWriter.appendRawLine("unknown", JSON.stringify({ method: "test" }));
5291
await logWriter.flush("unknown");

packages/agent/src/session-log-writer.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,31 @@ interface SessionState {
7373
pendingRawInputSnapshots: Map<string, StoredNotification>;
7474
}
7575

76+
function redactAuthorizationHeaders(value: unknown): unknown {
77+
if (Array.isArray(value)) {
78+
return value.map(redactAuthorizationHeaders);
79+
}
80+
if (value === null || typeof value !== "object") {
81+
return value;
82+
}
83+
84+
const record = value as Record<string, unknown>;
85+
if (
86+
typeof record.name === "string" &&
87+
record.name.toLowerCase() === "authorization" &&
88+
"value" in record
89+
) {
90+
return { ...record, value: "[REDACTED]" };
91+
}
92+
93+
return Object.fromEntries(
94+
Object.entries(record).map(([key, nestedValue]) => [
95+
key,
96+
redactAuthorizationHeaders(nestedValue),
97+
]),
98+
);
99+
}
100+
76101
export class SessionLogWriter {
77102
/**
78103
* When consecutive in-progress tool updates for one call span more than this
@@ -212,7 +237,9 @@ export class SessionLogWriter {
212237
const entry: StoredNotification = {
213238
type: "notification",
214239
timestamp,
215-
notification: message,
240+
notification: redactAuthorizationHeaders(
241+
message,
242+
) as StoredNotification["notification"],
216243
};
217244

218245
this.emitToSinks(sessionId, entry);

0 commit comments

Comments
 (0)