🫷 fix: Withhold Anthropic Custom Headers From User URLs (#13767)

This commit is contained in:
Danny Avila 2026-06-15 15:12:12 -04:00 committed by GitHub
parent 23c9226e9c
commit bf946975ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 3 deletions

View file

@ -407,14 +407,17 @@ describe('initializeCustom native Anthropic provider', () => {
mockGetCustomEndpointConfig.mockReturnValue(config);
return {
req: {
user: { id: 'user-1' },
user: { id: 'user-1', email: 'user@example.com' },
body: { conversationId: 'convo-1' },
config: {},
} as unknown as BaseInitializeParams['req'],
endpoint: 'Claude-Compatible',
model_parameters,
db: {
getUserKeyValues: jest.fn(),
getUserKeyValues: jest.fn().mockResolvedValue({
apiKey: 'sk-user-key',
baseURL: 'https://user-controlled.example.com',
}),
getUserKey: jest.fn(),
} as unknown as BaseInitializeParams['db'],
};
@ -446,6 +449,36 @@ describe('initializeCustom native Anthropic provider', () => {
expect(options.useLegacyContent).toBeUndefined();
});
it('withholds configured headers when the user supplies the base URL', async () => {
const params = createAnthropicParams({
provider: 'anthropic',
apiKey: 'sk-ant-custom',
baseURL: AuthType.USER_PROVIDED,
headers: {
Authorization: 'Bearer ${GATEWAY_SECRET}',
'X-User-Email': '{{LIBRECHAT_USER_EMAIL}}',
},
models: { default: ['claude-sonnet-4-5'] },
});
const options = await initializeCustom(params);
expect(mockValidateEndpointURL).toHaveBeenCalledWith(
'https://user-controlled.example.com',
'Claude-Compatible',
undefined,
);
expect(options.llmConfig).toHaveProperty(
'anthropicApiUrl',
'https://user-controlled.example.com',
);
const defaultHeaders = (
options.llmConfig as { clientOptions?: { defaultHeaders?: Record<string, string> } }
).clientOptions?.defaultHeaders;
expect(defaultHeaders?.Authorization).toBeUndefined();
expect(defaultHeaders?.['X-User-Email']).toBeUndefined();
});
it('applies customParams.paramDefinitions defaults on the native path', async () => {
const params = createAnthropicParams({
provider: 'anthropic',

View file

@ -111,17 +111,19 @@ function buildAnthropicCustomConfig({
baseURL,
modelOptions,
endpointConfig,
userProvidesURL,
}: {
apiKey: string;
baseURL: string;
modelOptions: AnthropicModelOptions;
endpointConfig: Partial<TEndpoint>;
userProvidesURL: boolean;
}): InitializeResultBase {
const result = getAnthropicLLMConfig(apiKey, {
modelOptions,
proxy: PROXY ?? undefined,
reverseProxyUrl: baseURL,
headers: endpointConfig.headers,
headers: userProvidesURL ? undefined : endpointConfig.headers,
addParams: endpointConfig.addParams,
dropParams: endpointConfig.dropParams,
/** Apply admin `customParams.paramDefinitions` defaults (e.g. promptCache,
@ -289,6 +291,7 @@ export async function initializeCustom({
baseURL,
modelOptions: modelOptions as AnthropicModelOptions,
endpointConfig,
userProvidesURL,
});
options.endpointTokenConfig = endpointTokenConfig;
} else {