Hi Bhasker,

The review is being worked through in GitHub, in issue #8, which links each
point to the pull request that addresses it:
https://github.com/skyfire-xyz/draft-skyfire-oauth-using-kyapay-tokens/issues/8

One change goes further than the review asked, so I'm calling it out here
(S4, https://github.com/skyfire-xyz/draft-skyfire-oauth-kyapay-token/pull/59).
In the KYAPay Token draft, `aud` now identifies the combination of
identities the issuer holds for the Target, and `tsi`, which identifies the
service under it, becomes REQUIRED. A recipient that has onboarded to the
issuer checks `aud` and `tsi`; any other recipient checks `tdm`, which
names the Target's host. Comments are welcome on the pull request or here.

Ankit


On Wed, Oct 21, 2026 06:21 PM, Bhasker Allam <[email protected]> wrote:

> Hi all,
>
> Below is a review of "Using KYAPay Tokens" [USING-KYAPAY],
> draft-skyfire-oauth-using-kyapay-tokens-01. Claims such as hid, aid
> and sti are  defined in the KYAPay Token draft [KYAPAY-TOKEN].
> Section numbers refer to [USING-KYAPAY] unless stated otherwise.
>
> Summary
> =======
>
> Most of the comments below come down to three high-level issues.
>
> 1. The bearer token carries personal and payment data.
>
>    The token is a signed JWT, not an encrypted one (Section 4.1). In
>    [KYAPAY-TOKEN], hid requires email and may carry name and phone, and
>    sti carries settlement details. Anyone who sees the header during
>    its lifetime can read the data and replay the token anywhere within
>    it's aud. Every hop that terminates TLS (CDN, WAF, bot manager,
>    origin) sees it. Sections 5.1 and 9.3 answer this with "MUST NOT log
>    or forward", which cannot be enforced or checked.
>
> 2. Admission without challenge.
>
>    Section 6.3 says a bot manager "SHOULD admit the request ... rather
>    than subjecting it to bot-blocking challenges." Combined with point
>    1, a captured or cheaply obtained token becomes an open gate at the
>    bot manager. Section 7.2 allows "progressive" verification that
>    starts with only an email check, so "verified human" can mean very
>    little. I don't have a good solution here, since the goal of the
>    draft is easy adoption using the existing OAuth and JWT framework.
>
> 3. Some things to clarify to avoid implementation divergence.
>
>    a. How intermediaries learn the aud set. Section 6.1 says to check
>       that the token is "intended for this recipient", but an
>       intermediary is not the recipient; the Target is. How will the
>       intermediary know the audience set?
>
>    b. Single-use vs. reusable. Section 8.3 asks for jti replay
>       detection, while Section 4.3 validates "once (per session)" and
>       mnr implies multiple requests.
>
>    c. What the human authorized. Section 6.6 treats a valid token as
>       evidence of a legitimate session, but the token does not name an
>       account or an action. Is hid meant to equal the account? Nothing
>       in the draft says so. Again this goes back to proof of
>       possession.
>
> Security comments
> =================
>
> S1. The token does not say which account it is for (Sections 6.6, 6.7,
>     8.8)
>
> Issue. A valid token with hid = attacker@example can be presented while
> logging into, or acting on, someone else's account. Section 6.6 says an
> ATO protector "SHOULD treat a validated KYAPay token ... as evidence
> that a session is a human-initiated agentic session." That is true, but
> it can be misread as evidence that the session is legitimate for this
> account. The authors have said there is no low-burden way to bind the
> token to an account today, and I agree.
>
> Suggestion.
>
> - Add a normative statement to 6.6 and 6.7, for example: "A KYAPay
>   token attests the identity of the principal who authorized the agent.
>   It does not convey authority over any account at the Target. ATO
>   protectors and CIAM systems MUST NOT treat a validated token as
>   authorization to access an account unless the token's principal has
>   been linked to that account."
>
> - List account binding as an open item next to step-up (6.5) and
>   revocation (8.7).
>
> - One possible path that keeps intermediary burden low is a DPoP change
>   I proposed on this list [DPOP-PROXY], which lets intermediaries
>   validate both the token and the sender.
>
> S2. Admission without challenge should depend on assurance (Sections
>     6.2, 6.3, 7.2)
>
> Issue. Section 6.3 says a bot manager "SHOULD admit the request ...
> rather than subjecting it to bot-blocking challenges." Section 7.2
> allows verification to begin with an email check. A bearer token
> obtained with a throwaway email then bypasses bot defenses on login,
> sign-up and checkout.
>
> Suggestion. Make the admission SHOULD conditional: "...SHOULD admit the
> request when the assurance levels in the token (Section 6.2) meet the
> Target's policy for the requested action." Add that per-hid, per-aid
> and per-apd rate and abuse limits still apply, and that sensitive
> actions MAY still be challenged.
>
> S3. Say the token is reusable, and drop jti replay detection (Sections
>     4.1, 4.3, 8.3)
>
> Issue. The token is meant to be reused within its roughly 5-minute
> lifetime. Section 4.3 validates it "once (per session)" and the payment
> claim mnr allows multiple requests. Yet Section 8.3 says verifiers
> "SHOULD use the jti claim to detect replay." That can't work in
> practice:
>
> - A Target is usually fronted by many intermediary instances (PoPs,
>   proxy fleets). Sharing jti state among them within the latency budget
>   in 6.3 ("no per-request callout") is not realistic.
>
> - Even a single-use token can't be enforced. Section 3.4 has the bot
>   manager, fraud manager, ATO protector and CIAM system all validate
>   the same token on the same request. Each layer would see the others'
>   use as a replay.
>
> Suggestion.
>
> - State in 4.1 that the token is reusable within its lifetime and aud.
>
> - List in-window replay within the aud set as an accepted risk of the
>   bearer model.
>
> - Reword 8.3 so jti is used for correlation, audit and issuer feedback
>   (6.10), not replay detection.
>
> - Point to proof of possession (4.3) as the only real fix, subject to
>   S8 below.
>
> S4. Define how intermediaries get the aud set (Sections 5.3, 6.1
>     step 5)
>
> Issue. aud works like a store-restricted gift card: the issuer limits
> which Targets can accept the token. An intermediary, though, is not the
> audience. Section 6.1 step 5 ("intended for this recipient") gives it
> no way to know which aud values are valid for the hosts it protects.
> Multi-tenant intermediaries front many Targets. How aud relates to tdm
> and tsi is also not stated.
>
> Suggestion.
>
> - Say that intermediaries obtain the acceptable aud (and tdm/tsi)
>   values per protected Target through configuration, for example as
>   part of each trusted issuer's configuration, and check the token
>   against that set.
>
> - Define the relationship between aud, tdm and tsi.
>
> - Say how an agent determines the aud for a given Target.
>
> S5. Check the issuer before fetching keys (Section 6.1 steps 3 and 4)
>
> Issue. Step 3 verifies the signature against the issuer's key set
> before step 4 checks that the issuer is trusted. Keys are found at
> iss + /.well-known/jwks.json, so a literal reading has verifiers
> fetching keys from any URL an attacker puts in iss (server-side request
> forgery, denial of service). Well-built verifiers already allowlist
> issuers, but the text should say so.
>
> Suggestion. Swap steps 3 and 4. Add: "A verifier MUST NOT retrieve key
> material for an issuer that is not in its configured set of trusted
> issuers."
>
> S6. Algorithm rules and token count (Sections 5.1, 6.1, References)
>
> Issue. The draft sets no algorithm rules. JWT Best Current Practices
> [RFC8725] is only an informative reference.
>
> Suggestion.
>
> - Make [RFC8725] a normative reference.
>
> - Require verifiers to use an algorithm allowlist tied to each issuer's
>   keys, and to reject "none" and symmetric algorithms.
>
> - In 5.1, let recipients reject a header with more than one token per
>   typ (at most 3 tokens). This caps verification cost per request.
>
> S7. Token leakage through the agent's runtime (Section 8)
>
> Issue. Tokens can leak through LLM transcripts, tool logs, and prompt
> injection. Section 7.1 mentions keeping credentials from the LLM, but
> Section 8 does not cover the threat. Proposed text is in the "Proposed
> text: new Section 8.x" part at the end of this message.
>
> S8. The planned proof-of-possession path reintroduces the rewriting
>     problem (Section 4.3)
>
> The bearer design is right not to depend on end-to-end request signing
> such as Web Bot Auth. Signing the request's components is heavy, and
> requests are routinely changed on the way to the origin. URL rewriting
> is common, and sites deliberately keep external and internal URLs
> separate so they don't expose internal architecture. When the signed
> request is what the client sent, every proxy that rewrites the request
> breaks verification or has to be given special handling.
>
> Issue. In Section 4.3 the issuer binds the agent's public key into the
> token (cnf), and the agent then signs each request, "a signature over
> the request (method, path, body digest, timestamp/nonce) using
> [RFC9421]", which is verified against cnf. The draft prefers this over
> a detached, DPoP-style proof [RFC9449]. Because the signature covers
> the path, the same rewriting fragility the bearer model avoids comes
> back: an intermediary that rewrites the URL, or an origin that sees
> only the internal path, can no longer verify it. Section 4.3 also notes
> that stopping replay of the signature "requires either per-Target nonce
> caches or binding the signature to the request content". That is the
> same shared-state problem across distributed intermediaries described
> in S3.
>
> Suggestion.
>
> - Make the rationale explicit in 4.2 and 4.3: why whole-request signing
>   is avoided, including the URL rewriting and internal/external URL
>   separation points above.
>
> - For the proof-of-possession path, say which components are covered,
>   and require a set that survives normal proxying. Alternatively, allow
>   verification at the first intermediary, before any rewrite.
>
> - Consider a DPoP-style proof designed for intermediaries as an
>   alternative. My DPoP proposal on this list [DPOP-PROXY] addresses
>   exactly this for URI-rewriting reverse proxies.
>
> Privacy and PCI comments
> ========================
>
> Sending the JWT in the clear is a reasonable choice: it reuses existing
> OAuth/JWT infrastructure and keeps integration simple. The comments
> below keep that model. They change what goes in the token, not how it
> is carried.
>
> P1. Replace personal data with a per-Target pseudonymous identifier
>     (Sections 9.1, 9.3; hid in [KYAPAY-TOKEN])
>
> Issue. hid requires email and may carry name and phone. Every
> intermediary receives it (9.3), and the same email reaches every
> Target, which lets sites track a person across all of them.
> Intermediaries don't need this data: bot, fraud and ATO decisions (6.3
> to 6.6) need a stable handle and assurance levels, not a name or email.
>
> Suggestion.
>
> - Carry an opaque, pseudonymous principal identifier that differs per
>   Target (pairwise, derived per aud), plus the verification and
>   assurance sub-claims.
>
> - A Target that needs the personal data (for example CIAM account
>   creation in 6.7) gets it from the issuer out of band, authenticated
>   as that Target, similar to the UserInfo endpoint in OpenID Connect
>   Core 1.0 [OIDC], Section 5.3.
>
> - Intermediaries can still rate-limit per principal, scope mitigations
>   (6.9) and send feedback (6.10) using the pseudonym.
>
> - Only the Target makes an issuer call, and only when it needs the
>   data, so the "no per-request callout" property in 6.3 holds for
>   intermediaries.
>
> P2. Keep payment data out of the token (Section 6.4; sti in
>     [KYAPAY-TOKEN])
>
> Issue. If sti can contain card-related data, every hop that sees the
> header may fall under PCI rules. Intermediary vendors and CDNs are
> unlikely to accept that.
>
> Suggestion. Apply the P1 pattern: sti carries a reference that the
> Target redeems with the issuer or payment processor. Add: "A KYAPay
> token MUST NOT contain primary account numbers or other cardholder
> data." Amount, currency and limits (amt, cur, mnr) can stay, since
> fraud managers use them (6.4).
>
> P3. Make aid.creation_ip optional ([KYAPAY-TOKEN])
>
> Issue. creation_ip is REQUIRED. It is personal data, and Section 6.3
> already says network-origin claims are "a weak corroborating signal
> only."
>
> Suggestion. Make it OPTIONAL.
>
> Protocol and compatibility comments
> ===================================
>
> C1. Header grammar and Structured Fields disagree (Sections 5.1, 10.1)
>
> Section 5.1 defines its own ABNF, while 10.1 registers KYAPay-Token as
> a Structured Field of type List. Under Structured Field Values for HTTP
> [RFC9651], a malformed member makes the whole field fail to parse. That
> conflicts with 5.1's "MUST ignore a member it cannot parse ... while
> continuing to process the remaining members." Pick one: define the
> field as an sf-list of sf-string (or sf-token) and drop the custom
> ABNF, or drop the Structured Field registration.
>
> C2. Header size (Section 5.1)
>
> Up to three JWTs carrying identity and payment claims can exceed common
> header limits (nginx header buffers, load balancer and CDN caps). Give
> a recommended maximum field size, or at least a note. The P1 and P2
> changes would shrink tokens considerably.
>
> C3. Browser agents and CORS (Sections 3.3, 5.1)
>
> A custom request header on a cross-origin fetch triggers a CORS
> preflight. Page scripts can't send it unless the site allows it in
> Access-Control-Allow-Headers. Browser-use agents also can't easily add
> headers to page navigations. Say which requests carry the token
> (top-level navigations, API calls, sub-resources), and qualify the
> "zero merchant tech lift" claim for browser-based agents.
>
> C4. No challenge or error response (Sections 6.5, 8.8)
>
> A Target cannot signal "token required", "token rejected" or "higher
> assurance needed." For step-up, which 6.5 lists as open, consider
> reusing OAuth 2.0 Step Up Authentication Challenge Protocol [RFC9470],
> which already defines WWW-Authenticate challenges for insufficient
> authentication. It would also help to explain why the draft uses a new
> header rather than an Authorization scheme (presumably to avoid
> clashing with the site's own authentication).
>
> Proposed text: new Section 8.x, Token Exposure in the Agent Runtime
> ===================================================================
>
> Suggested for insertion after Section 8.5 (Compromised Agent Host). It
> complements 8.5: that section covers malware using the agent's key,
> while this one covers the token leaving the agent through its own
> normal operation.
>
>    8.x. Token Exposure in the Agent Runtime
>
>    Agents driven by language models process untrusted content and
>    record their activity in ways that conventional HTTP clients do not.
>    A KYAPay token can therefore leave the agent through normal
>    operation, without the agent host being compromised. Examples
>    include:
>
>    o  the token appearing in model context, conversation transcripts,
>       or tool-call inputs and outputs that are logged, retained, or
>       sent to a model provider;
>
>    o  agent tracing, observability, or debugging systems that record
>       outbound request headers;
>
>    o  prompt injection, where content retrieved from a website or tool
>       instructs the agent to reveal the token or to include it in a
>       request to a party other than the intended Target.
>
>    For a bearer token (Section 4.1), anyone who obtains a leaked token
>    can use it at any audience in its aud until it expires. Audience
>    binding does not help if the attacker presents the token at a
>    legitimate Target.
>
>    Agent developers and KYAPay Token Issuers SHOULD mint and attach
>    tokens in deterministic components (Section 7.1) whose outputs are
>    not placed in model context. Agents SHOULD attach a token only to
>    requests whose destination matches the token's audience (aud, and
>    tdm or tsi where used), and the component that attaches it MUST
>    make that decision without relying on model output. Agent runtimes
>    MUST NOT record KYAPay token values in logs, traces, or
>    transcripts. Agents SHOULD request a new token for each Target and
>    task rather than reusing one broadly, and SHOULD request the
>    shortest lifetime that fits the task. Proof of possession (Section
>    4.3) reduces this exposure only if the private key is also kept out
>    of model context.
>
> References
> ==========
>
> [USING-KYAPAY]
>    Agarwal, A., Jones, M. B., and S. Thumma, "Using KYAPay Tokens",
>    draft-skyfire-oauth-using-kyapay-tokens-01,
>
> https://datatracker.ietf.org/doc/draft-skyfire-oauth-using-kyapay-tokens/
>    Editor's copy:
>
> https://skyfire-xyz.github.io/draft-skyfire-oauth-using-kyapay-tokens/draft-skyfire-oauth-using-kyapay-tokens.html
>
> [KYAPAY-TOKEN]
>    Agarwal, A. and M. B. Jones, "KYAPay Token",
>    draft-skyfire-oauth-kyapay-token-01,
>
> https://datatracker.ietf.org/doc/html/draft-skyfire-oauth-kyapay-token-01
>
> [DPOP-PROXY]
>    Allam, B., DPoP proposal for URI-rewriting reverse proxies, message
>    to the OAuth WG mailing list,
>
> https://mailarchive.ietf.org/arch/msg/oauth/F-UUNUUuZJihx_Qpms6EGsItoyc/
>
> [RFC8725]
>    Sheffer, Y., Hardt, D., and M. Jones, "JSON Web Token Best Current
>    Practices", BCP 225, RFC 8725,
>    https://www.rfc-editor.org/rfc/rfc8725
>
> [RFC9421]
>    Backman, A., Ed., Richer, J., Ed., and M. Sporny, "HTTP Message
>    Signatures", RFC 9421,
>    https://www.rfc-editor.org/rfc/rfc9421
>
> [RFC9449]
>    Fett, D., Campbell, B., Bradley, J., Lodderstedt, T., Jones, M., and
>    D. Waite, "OAuth 2.0 Demonstrating Proof of Possession (DPoP)",
>    RFC 9449,
>    https://www.rfc-editor.org/rfc/rfc9449
>
> [RFC9470]
>    Bertocci, V. and B. Campbell, "OAuth 2.0 Step Up Authentication
>    Challenge Protocol", RFC 9470,
>    https://www.rfc-editor.org/rfc/rfc9470
>
> [RFC9651]
>    Nottingham, M. and P-H. Kamp, "Structured Field Values for HTTP",
>    RFC 9651,
>    https://www.rfc-editor.org/rfc/rfc9651
>
> [OIDC]
>    Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C.
>    Mortimore, "OpenID Connect Core 1.0",
>    https://openid.net/specs/openid-connect-core-1_0.html
>
> Thanks,
> Bhasker Allam
> _______________________________________________
> OAuth mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
>
_______________________________________________
OAuth mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to