Spigniv73 opened a new issue, #14151:
URL: https://github.com/apache/apisix/issues/14151

   ## Summary
   
   `ai-cache`'s request fingerprint omits two things that determine the 
upstream response:
   the client headers it forwards and the instance `auth` (header/query). Its 
own comment calls the
   fingerprint the *"Identity of the EFFECTIVE upstream request"* — but 
`ai-proxy` forwards
   `core.request.headers(ctx)` verbatim and uses `auth.header`/`auth.query`, so 
two requests with an
   identical body can hit the same cache cell while the effective upstream 
request differs.
   
   ## Where (pin `b6deb41`; same file on `main` and in 3.19.0)
   
   `apisix/plugins/ai-cache/key.lua:59-116` — the hashed representation 
contains only:
   
   ```lua
   return {
       client = client,               -- protocol, params, messages
       effective = {
           provider = inst.provider,
           model = ...,
           options = inst.options,
           llm_options = ov.llm_options,
           request_body = ov.request_body,
           endpoint = ov.endpoint,
       },
   }
   ```
   
   No `client_headers`, no `auth`. The counterpart is explicitly the opposite:
   
   * `apisix/plugins/ai-proxy/base.lua:291` — `extra_opts.client_headers = 
core.request.headers(ctx)`
   * `apisix/plugins/ai-transport/http.lua:93-96` — every `client_headers` 
entry is copied into the
     outbound header set
   * `apisix/plugins/ai-proxy/schema.lua` — `auth.header` / `auth.query` / 
`instances.auth.*` are part of
     the instance definition
   
   ## Proof of the collision (unit, real `key.lua`)
   
   ```
   digest anthropic-version=2023-06-01 : 26e80b5b…d2409
   digest anthropic-version=2099-01-01 : 26e80b5b…d2409
   identical? true
   repr fields:
     client    = 
{"protocol":"anthropic","params":{"stream":false},"messages":{}}
     effective = 
{"options":{...},"model":"claude-3-5-sonnet","provider":"anthropic"}
   ```
   
   Repro (resty against the checkout, stubs only for `apisix.core`):
   
   ```bash
   resty --no-stream -I <apisix-checkout> poc_cache.lua
   ```
   
   ## Impact
   
   * A response can be replayed for a request whose `anthropic-version` / 
`anthropic-beta` (or any
     other response-determining header) differs → wrong or outdated answer.
   * With `ai-proxy-multi` (or `share_across_routes`) two instances that share 
provider/model/endpoint but
     differ in `auth` collide, so a response fetched with one credential can be 
served to a caller routed
     to another instance.
   * CVSS 3.1 `AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N` = 6.5. Client-controlled: 
the header comes from the
     downstream caller.
   
   ## Suggestion
   
   Add `client_headers` (at least a deterministic subset/normalised form) and 
the instance `auth`
   material to `build_repr`. The existing `llm_options`/`endpoint` handling 
shows the pattern: anything
   `build_request` consumes belongs in the fingerprint.
   
   ## Notes
   
   Found while auditing `b6deb41`. `apisix/plugins/ai-cache/key.lua` on `main` 
still has the same
   structure, and there is no matching issue in the tracker. The digest proof 
is hard for the collision
   itself; the exact per-provider blast radius (which upstreams vary on which 
header) is our inference.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to