Skip to content

Bump hono from 4.11.3 to 4.11.7 in /pinning-webui#14

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/pinning-webui/hono-4.11.7
Closed

Bump hono from 4.11.3 to 4.11.7 in /pinning-webui#14
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/pinning-webui/hono-4.11.7

Conversation

@dependabot
Copy link
Copy Markdown

@dependabot dependabot Bot commented on behalf of github Jan 27, 2026

Bumps hono from 4.11.3 to 4.11.7.

Release notes

Sourced from hono's releases.

v4.11.7

Security Release

This release includes security fixes for multiple vulnerabilities in Hono and related middleware. We recommend upgrading if you are using any of the affected components.

Components

IP Restriction Middleware

Fixed an IPv4 address validation bypass that could allow IP-based access control to be bypassed under certain configurations.

Cache Middleware

Fixed an issue where responses marked with Cache-Control: private or no-store could be cached, potentially leading to information disclosure on some runtimes.

Serve Static Middleware (Cloudflare Workers adapter)

Fixed an issue that could allow unintended access to internal asset keys when serving static files with user-controlled paths.

hono/jsx ErrorBoundary

Fixed a reflected Cross-Site Scripting (XSS) issue in the ErrorBoundary component that could occur when untrusted strings were rendered without proper escaping.

Recommendation

Users are encouraged to upgrade to this release, especially if they:

  • Use IP Restriction Middleware
  • Use Cache Middleware on Deno, Bun, or Node.js
  • Use Serve Static Middleware with user-controlled paths on Cloudflare Workers
  • Render untrusted data inside ErrorBoundary components

Security Advisories & CVEs

... (truncated)

Commits

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps [hono](https://github.com/honojs/hono) from 4.11.3 to 4.11.7.
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](honojs/hono@v4.11.3...v4.11.7)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.11.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels Jan 27, 2026
@dependabot @github
Copy link
Copy Markdown
Author

dependabot Bot commented on behalf of github Feb 20, 2026

Superseded by #19.

@dependabot dependabot Bot closed this Feb 20, 2026
@dependabot dependabot Bot deleted the dependabot/npm_and_yarn/pinning-webui/hono-4.11.7 branch February 20, 2026 18:45
ehsan6sha added a commit that referenced this pull request May 19, 2026
Implements the issuer side of the "seed IS the user" identity model
agreed with the maintainer (audit F-A1 / F-A3 redesign, 2026-05-18).
Matches the cryptographic primitives shipped in fula-api
(functionland/fula-api@7fa2f32) and the
specification on functionland/fula-api#14.

Mode B / Mode C clients prove possession of the seed by signing a
challenge nonce with an Ed25519 keypair the seed deterministically
produces. The seed never leaves the client. The webui mints a JWT
with `sub = effective_user_id_hex` (the same 16-byte BLAKE3 derivation
the client computes locally). The fula-cli gateway treats `sub`
opaquely; no gateway change is required.

Because Mode B/C `effective_user_id` values are seed-derived 128-bit
hashes of high-entropy input, the gateway's published users-index
CBOR is non-enumerable for these users — closing F-A3 naturally
without a separate dual-publish design.

New file `server/services/seedAuth.ts`:

- Strict input validators (hex32 regex; exact-length base64 decoders).
- Ed25519 verification via Node's built-in `crypto.verify`, with raw
  32-byte public keys wrapped in the SPKI prefix Node expects.
- Domain-separated `buildSignedTranscript(purpose, uid, challenge)`
  so a signature issued for `register-mode-b` can't be replayed at
  `sign-in`, and a signature for one uid can't be replayed for
  another (Codex advisor 2026-05-18).
- In-memory challenge store with 60-second TTL, single-use semantics,
  and a periodic sweep that runs on a 60-second interval (unref'd so
  it doesn't keep the process alive). Single-process server today; if
  ever scaled horizontally, swap for Redis.
- `insertOrAssertSeedUser` handles the squatting case: same
  effective_user_id with a different public_key throws
  `PublicKeyMismatchError` (mapped to HTTP 409 PUBLIC_KEY_MISMATCH).
  Same key is idempotent (returns the existing row).

New endpoints in `server/app.ts`:

- `POST /auth/register-mode-b`  — first sign-up (Google/Apple OAuth +
  seed). Verifies OAuth via existing `google-auth-library` /
  `apple-signin-auth`; verifies Ed25519 signature; transactional
  INSERT into `seed_users` + `webui_users`; mints JWT. Response
  includes `has_mode_a` so the client can warn the user that their
  new vault is separate from any existing Mode A account on the same
  OAuth identity (Gemini advisor 2026-05-18).
- `POST /auth/register-mode-c`  — same shape minus OAuth. The
  effective_user_id derivation is `BLAKE3(domain || NFKC(seed))[..16]`
  client-side; two users with identical seeds coincidentally collide
  — by design (the seed IS the identity; use a high-entropy
  passphrase).
- `POST /auth/challenge`        — `{effective_user_id_hex}` → returns
  a fresh 32-byte random nonce (base64). Single-use, 60-second TTL.
  Returns 404 USER_NOT_FOUND on unknown id (the id is already public
  via the gateway's CBOR, so hiding it adds no security).
- `POST /auth/sign-in`          — verifies the signed challenge using
  the stored public_key, mints a fresh JWT, touches `last_used_at`.

The minted JWT reuses the existing `generateJwtApiKey` helper so the
shape is byte-identical to today's API keys
(`{sub, iat, scope, jti}`), just with `sub = effective_user_id_hex`
(32 hex chars) instead of `SHA-256(email)` (64 hex chars). Both
encodings fit in `webui_users.user_id VARCHAR(64)`.

New DB table `seed_users`:

    CREATE TABLE seed_users (
      effective_user_id VARCHAR(32) PRIMARY KEY,
      mode CHAR(1) NOT NULL CHECK (mode IN ('B','C')),
      public_key BYTEA NOT NULL,
      oauth_sub VARCHAR(255),
      provider VARCHAR(16),
      registered_at TIMESTAMPTZ DEFAULT NOW(),
      last_used_at TIMESTAMPTZ
    )

Plus a partial index on `oauth_sub WHERE NOT NULL`. Migration runs
inside the existing `initializeDatabase` block alongside the other
table migrations.

Mode B users get a fresh `webui_users` row keyed by their
effective_user_id — explicitly NOT shared with any Mode A account
for the same Google/Apple identity. This matches the maintainer's
"treat different modes as different users" decision; the consequence
is that credit balances / wallets / pins are per-vault, not
per-OAuth-identity. The `webui_users` row stores no email or
profile information (the OAuth binding lives only in
`seed_users.oauth_sub`).

Tighter rate limit on the seed-auth endpoints (30 requests per hour
per IP) than the generic API limit, to bound registration spam +
challenge-store growth. Skipped under `options.skipRateLimit = true`
for tests.

Tests in `tests/seedAuth.test.ts` (15 cases — vitest + supertest):

- happy-path registration → 200, JWT sub matches uid, mode=C.
- Idempotent re-registration (same key) → 200.
- Squatting (different key, same uid) → 409 PUBLIC_KEY_MISMATCH.
- Bad signature → 401 SIGNATURE_INVALID.
- Cross-purpose signature replay (register sig at sign-in) → 401.
- Malformed effective_user_id_hex (5 variants) → 400 VALIDATION_ERROR.
- Bad public_key length → 400 VALIDATION_ERROR.
- `/auth/challenge` unknown user → 404 USER_NOT_FOUND.
- `/auth/challenge` known user → 200 + 32-byte nonce.
- `/auth/sign-in` happy path → 200 + JWT.
- `/auth/sign-in` challenge replay → 401 CHALLENGE_INVALID.
- `/auth/sign-in` wrong signature → 401 SIGNATURE_INVALID.
- `/auth/sign-in` challenge tampering → 401 CHALLENGE_INVALID.
- `/auth/sign-in` no prior challenge → 401 CHALLENGE_INVALID.
- `/auth/sign-in` cross-user signature replay → 401 SIGNATURE_INVALID.

Tests are skipped on machines without PostgreSQL reachable (same
pattern as the existing `api.test.ts`).

Out of scope for this change (separate follow-ups):

- Free-tier abuse mitigation: an attacker with a leaked Google ID
  token could call `register-mode-b` once per attacker seed and get
  a fresh Mode B vault per call. Each vault would get its own
  default credits. Mitigation discussed but deferred — bind free
  tier to `oauth_sub` rather than `effective_user_id` in
  creditService. Tracked on
  functionland/fula-api#14.
- Mode-C recovery mnemonic UX (Flutter side).
- FxFiles `auth_service.dart` integration calls to these endpoints.

Refs:
- fula-api commit 7fa2f32 (crypto primitives + FFI)
- fula-api issue #14 (full design spec)
- Gemini advisor 2026-05-18 (error UX, vault labeling)
- Codex advisor 2026-05-18 (transactional insert, SPKI wrapping,
  domain-separated transcript, strict validation)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ehsan6sha added a commit that referenced this pull request May 19, 2026
Three security/correctness fixes for the issuer endpoints, closing
the open audit items on functionland/fula-api#14.

## Finding #1 (CRITICAL) — Registration replay

`POST /auth/register-mode-b` and `/auth/register-mode-c` previously
accepted a CLIENT-generated challenge and verified only the Ed25519
signature over it. The challenge was never tracked as single-use, so
anyone who captured a valid registration request body could replay
it to mint fresh JWTs forever. Severity is amplified by the design
choice that JWTs have no `exp` claim (DT-1): each replay produced
a perpetually-valid token, killable only by rotating `JWT_SECRET`.

Fix: extended the existing `POST /auth/challenge` endpoint to accept
a `purpose` parameter (`'sign-in'` | `'register-mode-b'` | `'register-mode-c'`)
defaulting to `'sign-in'` for back-compat. The two register endpoints
now consume the challenge from the in-memory store the same way
`/auth/sign-in` already does: `challengeStore.takeIfValid(uid, 'register-mode-{b,c}')`
then `crypto.timingSafeEqual` against the submitted bytes. Replay of
a captured body fails at the first step (challenge already consumed)
and returns HTTP 401 `CHALLENGE_INVALID`.

Sign-in callers still trigger USER_NOT_FOUND when the target uid is
unknown; register callers skip that check because they're creating
the user.

## Finding #4 (IMPORTANT) — `has_mode_a` was wrong

The `register-mode-b` response had a `has_mode_a: boolean` field
intended to surface "this OAuth identity already has a Mode A vault
that the new Mode B sign-up is SEPARATE from". The previous logic
counted `seed_users` rows with the same `oauth_sub` — which detects
"another seed-based vault", NOT "a Mode A account". Mode A users
live in `webui_users` keyed by `SHA-256(lowercase(email))`, never in
`seed_users`.

Fix: replaced `checkModeAExistsForOauthSub(oauthSub)` with
`checkModeAExistsForEmail(email)` that does a direct PK lookup on
`webui_users` using `emailToUserId(verifiedOauthEmail)`. Captures
the OAuth-verified email alongside the sub in the existing Google /
Apple verification block. Apple's relay-email behavior on subsequent
sign-ins (no email returned after first sign-in) is an acceptable
false-negative — `has_mode_a = false` is the safe default.

The FxFiles client wires the result into a "Existing vault detected"
warning dialog on the Mode B sign-up success path so the user knows
their new Maximum-security vault is independent of their existing
Standard-security one (Gemini advisor 2026-05-18).

## Finding #5 (IMPORTANT) — `encrypted_email = NULL` audit

Mode B / Mode C `webui_users` rows used to be inserted with
`encrypted_email = NULL`. Codex flagged this as a downstream risk:
any future code that reads the column without null-guards could
misattribute or crash for these users. A grep across the codebase
found only INSERT sites for the column today, but the surface area
is non-trivial (admin tools, future SELECT joins, possible backup /
audit scripts).

Fix per maintainer's direction: store the AES-256-GCM-encrypted
`effective_user_id_hex` in the column instead of NULL. "Email is
essentially user-id all over the system" — treating the canonical
seed-user-id as the email gives downstream code a non-null
opaque value to work with. The actual OAuth email of a Mode B user
is NOT persisted (the OAuth binding still lives only in
`seed_users.oauth_sub`), so this change does NOT introduce new PII
exposure.

## Tests

`tests/seedAuth.test.ts`:
- AUDIT-1 replay: register a uid via the new server-issued-challenge
  flow, replay the captured body, expect 401 CHALLENGE_INVALID.
- AUDIT-5 encrypted_email non-null: register Mode C, query
  `webui_users.encrypted_email`, assert non-null and non-empty.

Existing 15 tests updated to use the new `obtainRegisterChallenge`
helper (call `/auth/challenge` with the appropriate purpose before
registering) — they previously passed client-generated nonces and
would now fail with `CHALLENGE_INVALID`. Total: 17 vitest cases.

Tests skip on machines without PostgreSQL — same pattern as the
existing `api.test.ts`. Run via `npm test` against a populated DB.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants