Environment
Product: Apigee Edge for Private Cloud
Version: 4.53.00.00
Component: ServiceCallout Policy + AssignMessage Policy
Severity: Medium (HTTP Protocol Violation)
Summary
When using ServiceCallout policy to call a backend target, Apigee incorrectly adds an “authority” response header to the HTTP response returned to clients. This violates HTTP specifications, as “authority” (or :authority in HTTP/2) is strictly a request header and should never appear in responses.
Issue Description
We have observed that Apigee adds an “authority” header to HTTP responses when using the ServiceCallout policy in combination with AssignMessage policy to copy response data. This occurs even though:
The backend target service does NOT return any “authority” or “Host” header in its response (verified with direct curl testing)
The AssignMessage policy explicitly copies only specific headers (Content-Type in our case)
The backend developers confirmed their code does not set any such headers
Steps to Reproduce
1. Proxy Configuration
Create an API proxy with a ServiceCallout policy:
<Request variable="customRequest"/>
<Response>customResponse</Response>
<HTTPTargetConnection>
<URL>http://notfound</URL>
</HTTPTargetConnection>
2. Request Creation Policy
Create request using AssignMessage:
<Copy source="request">
<Verb>true</Verb>
<Headers>
<Header name="Accept"/>
</Headers>
<QueryParams>true</QueryParams>
<Payload>true</Payload>
</Copy>
<AssignTo createNew="true" transport="http" type="request">customRequest</AssignTo>
3. Response Handling Policy
Copy response back to client:
<Copy source="customResponse">
<StatusCode>true</StatusCode>
<ReasonPhrase>true</ReasonPhrase>
<Payload>true</Payload>
<Headers>
<Header name="Content-Type"/>
</Headers>
</Copy>
<AssignTo createNew="false" transport="http" type="response"/>
4. Call the API
Make an HTTP/2 request to the Apigee proxy endpoint.
Expected Behavior
The response to the client should contain ONLY the headers returned by the backend target service, plus any explicitly added by Apigee policies. The “authority” header should NOT be present in the response.
Actual Behavior
The response contains an “authority” header that was never returned by the backend service. When traced using Apigee’s trace tool, the “authority” header appears in the response headers returned to the client.
Verification
We verified the backend behavior by calling it directly:
curl --http2 -I -v https://backend-service.example.com/api/endpoint
Result: Backend response does NOT contain any “authority” or “Host” header (see backend response headers below).
Backend Response Headers (Direct Call):
HTTP/2 200
content-type: application/json; charset=utf-8
date: Tue, 06 Jan 2026 07:22:36 GMT
…
content-length: 467
strict-transport-security: max-age=31536000; includeSubDomains; preload;
Impact
Protocol Violation: HTTP specifications state that “authority” (HTTP/2 :authority pseudo-header) is strictly a request header and must not appear in responses
Client Compatibility: Some HTTP clients may reject or mishandle responses containing invalid headers
Security Concern: Leaking internal routing information (authority/host) in responses
Workaround
We can work around this issue by explicitly removing the header in the AssignMessage policy:
<Copy source="customResponse">
<StatusCode>true</StatusCode>
<ReasonPhrase>true</ReasonPhrase>
<Payload>true</Payload>
<Headers>
<Header name="Content-Type"/>
</Headers>
</Copy>
<Remove>
<Headers>
<Header name="authority"/>
<Header name=":authority"/>
<Header name="Host"/>
</Headers>
</Remove>
<AssignTo createNew="false" transport="http" type="response"/>
Root Cause Analysis
Based on our investigation, we believe this occurs because:
Apigee’s ServiceCallout internally stores request metadata (including the Host/authority header used to call the target)
When copying the response using , Apigee incorrectly includes this request metadata in the response object
Even though we specify only certain headers to copy, the metadata leaks through
Please investigate and fix this issue in future releases. The workaround is functional but should not be necessary for proper HTTP protocol compliance.