Skip to content

Fix/py middleware gate resolution ssrf#73

Merged
ucekmez merged 2 commits into
mainfrom
fix/py-middleware-gate-resolution-ssrf
Jul 1, 2026
Merged

Fix/py middleware gate resolution ssrf#73
ucekmez merged 2 commits into
mainfrom
fix/py-middleware-gate-resolution-ssrf

Conversation

@ucekmez

@ucekmez ucekmez commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Scope

  • Spec / schema only
  • TypeScript package(s)
  • Python package(s)
  • Tests / CI
  • Docs / examples
  • Other: ___

Checklist

  • I read CONTRIBUTING.md and CODE_OF_CONDUCT.md.
  • Tests added or updated where appropriate (npm test / pytest in affected packages).
  • Breaking change to public API or normative spec? If yes, describe impact and note CHANGELOG.md / migration path.
  • Documentation updated for user-visible behavior.

Notes for reviewers

ucekmez added 2 commits June 10, 2026 22:43
The auth adapters in `@eep-dev/middleware` (TypeScript) and `eep-middleware`
(Python) turned attacker-controlled credentials into trusted EEP proofs:

- `JWTAuthAdapter` base64-decoded the JWT payload and emitted
  `{type:"identity", method:"did_verified"}` and capability proofs WITHOUT
  verifying the signature or the `alg` header. An `alg: none` token, or any
  forged token, was accepted at face value.
- The TypeScript `OAuthAuthAdapter` derived capability proofs straight from a
  client-supplied `X-OAuth-Scope` header (or `scope` query param), so a caller
  could assert any scope it wanted.

Both adapters now fail closed:

- `JWTAuthAdapter` rejects `alg: none` unconditionally, verifies HS256/384/512
  signatures against a configured `secret` (constant-time compare), delegates
  asymmetric/custom algorithms to a `verifyToken` / `verify_token` callback,
  enforces `exp`/`nbf`/`iat` with a configurable clock-skew tolerance (60s
  default), and emits no proofs (warning once) when no verification material is
  configured. The algorithm router never lets an HMAC secret verify an
  asymmetric token, and never lets the asymmetric callback rubber-stamp an HS
  token. An explicit `algorithms` allowlist is supported.
- `OAuthAuthAdapter` requires an RFC 7662 `introspect` callback and reads scope
  and subject only from the authorization server's response. A client-supplied
  `X-OAuth-Scope` header is ignored.

The TypeScript `JWTAuthAdapterOptions` is extended (non-breaking) with `secret`,
`verifyToken`, `algorithms`, and `clockToleranceSec`; `OAuthAuthAdapter` now
takes a required `{ introspect }` option (mirrors `APIKeyAuthAdapter`'s required
resolver). `EEPServer` defaults are unaffected (it uses `HeaderProofAuthAdapter`).

Tests cover signed/forged/tampered/expired tokens, `alg: none`, algorithm
confusion, the allowlist, callback delegation (sync + async), introspection
states, and fail-closed construction. Coverage of the changed files is 100%
(TS jwt.ts/oauth.ts; Python jwt.py at 100% statements + branches, package gate
`--cov-fail-under=100` satisfied). READMEs and CHANGELOG updated.

Surfaced by the EEP protocol audit.

Signed-off-by: Ugur Cekmez <ucekmez@gmail.com>
fix(middleware): fail-closed JWT/OAuth auth adapters (C2)
Copilot AI review requested due to automatic review settings July 1, 2026 21:50
@ucekmez ucekmez merged commit 00b11d7 into main Jul 1, 2026
20 of 21 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens authentication in both the TypeScript @eep-dev/middleware and Python eep-middleware packages by switching adapters to fail-closed behavior and only emitting EEP proofs after credentials are verified (JWT signature verification / OAuth token introspection). It also updates docs/tests and records the security change in the changelog.

Changes:

  • TypeScript: JWTAuthAdapter now verifies HS* signatures (or delegates via verifyToken), enforces alg !== none, and applies temporal claim checks; OAuthAuthAdapter now requires RFC 7662-style introspection and no longer trusts client-supplied scope headers.
  • Python: JWTAuthAdapter now verifies JWT signatures (HS* or delegated) and enforces temporal claims; tests expanded significantly to cover edge cases and fail-closed behavior.
  • Docs/exports/changelog updated to describe the new verification requirements and fail-closed behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/eep-middleware-python/tests/test_auth.py Expands JWT auth tests to cover signature verification, alg allowlists, and temporal-claim checks.
packages/eep-middleware-python/README.md Documents fail-closed JWT verification behavior and configuration options.
packages/eep-middleware-python/eep_middleware/auth/jwt.py Implements verified-claims flow (HMAC verification or delegated verification) + temporal checks.
packages/@eep-dev/middleware/src/index.ts Re-exports JWT/OAuth adapter option and helper types.
packages/@eep-dev/middleware/src/auth/oauth.ts Switches OAuth adapter to introspection-based verification and emits proofs from AS response only.
packages/@eep-dev/middleware/src/auth/oauth.test.ts Adds comprehensive tests for fail-closed introspection behavior.
packages/@eep-dev/middleware/src/auth/jwt.ts Implements JWT signature verification (HS* or delegated), alg checks, and temporal checks.
packages/@eep-dev/middleware/src/auth/jwt.test.ts Adds comprehensive tests for fail-closed JWT verification and delegation behavior.
packages/@eep-dev/middleware/README.md Documents the authentication adapters’ verification semantics and configuration patterns.
CHANGELOG.md Records the security implications and behavior change for both middleware packages.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

token: string,
payload: Record<string, unknown>
): Promise<Record<string, unknown> | null> {
if (alg in HMAC_ALGORITHMS) {
return proofs;
const signingInput = `${parts[0]}.${parts[1]}`;
const expected = createHmac(HMAC_ALGORITHMS[alg], this.secret).update(signingInput).digest();
const provided = Buffer.from(parts[2].replace(/-/g, "+").replace(/_/g, "/"), "base64");

Auth adapters turn inbound credentials into EEP **proofs**. They fail closed: a token is trusted
only after its signature (or the authorization server) is verified. An adapter that cannot verify
anything emits no proofs (and logs a one-time warning) rather than trusting attacker-controlled input.
```typescript
import { JWTAuthAdapter } from "@eep-dev/middleware";

const auth = new JWTAuthAdapter({ secret: process.env.JWT_SECRET });
Comment on lines +121 to +123
from eep_middleware.auth.jwt import JWTAuthAdapter

auth = JWTAuthAdapter(secret=os.environ["JWT_SECRET"])
`did_verified` / capability proofs, always rejects `alg: none`, and rejects expired
tokens. Configure a shared `secret` for HS256/384/512, or a `verify_token` callback
(sync or async, returning the verified claims or `None`) for asymmetric algorithms.
Without either it emits no proofs and warns once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants