stop handing a member's turn the owner's mcp config, and close the file
host found a live credential exposure while answering my question about what else the member branch missed. It was outside the diff, and predates all of it. MCP-CONFIG WAS NOT BRANCHED. mcpHostPath is module-level, written once at the owner's bootstrap, and was applied to every turn. Its env block carries OFFICER_AUTH_TOKEN, a 30-day JWT signing as the owner — so a member's turn would have spawned their MCP server holding it. Now inside the params.member ternary alongside the binary and the spawn, for the reason already written there: these values say whose turn this is and have to move together. A member gets none. What they should get instead is undecided, and undefined beats the owner's. THE FILE WAS 0644. Written with a bare writeFileSync into a 755 directory, on a host where `terminal` is granted to every role by default — so any member could cat it and hold owner-level API access on loopback. host verified that as a real member on the production host rather than reasoning about it. Now 0600. The mode is the only half of that which is code. The token has been world-readable and stays compromised until rotated, the directory chain above it is still 755, and neither is fixable from a commit. Both written up for the owner in COMMS 05, along with why I am stopping here rather than continuing: the next commit should be the rotation, not more feature work stacked on top of an open exposure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -129,7 +129,15 @@ function generateMcpConfig(): string {
|
||||
},
|
||||
},
|
||||
};
|
||||
writeFileSync(join(contextDir, 'mcp-host.json'), JSON.stringify(hostConfig));
|
||||
// 0600, because this file's `env` block carries OFFICER_AUTH_TOKEN — a 30-day JWT that signs as the owner.
|
||||
// It was written at the default 0644 inside a 755 directory, and `terminal` is granted to every role by
|
||||
// default, so any member with a shell could `cat` it and hold owner-level API access against
|
||||
// OFFICER_API_URL on loopback. Verified as a real member on the production host, not reasoned about.
|
||||
//
|
||||
// The mode is only the half of this that is code. The directory chain above it still allows traversal and
|
||||
// listing, and a token that has been world-readable stays compromised however the file is chmod'ed
|
||||
// afterwards — it has to be rotated. Both are the owner's, and both are written up in COMMS.
|
||||
writeFileSync(join(contextDir, 'mcp-host.json'), JSON.stringify(hostConfig), { mode: 0o600 });
|
||||
|
||||
return join(contextDir, 'mcp-host.json');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user