Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update dependency hono to v4 [SECURITY] #189

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

renovate[bot]
Copy link
Contributor

@renovate renovate bot commented Dec 15, 2023

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
hono (source) ^2.6.2 -> ^4.0.0 age adoption passing confidence

GitHub Vulnerability Alerts

CVE-2023-50710

Impact

The clients may override named path parameter values from previous requests if the application is using TrieRouter. So, there is a risk that a privileged user may use unintended parameters when deleting REST API resources.

TrieRouter is used either explicitly or when the application matches a pattern that is not supported by the default RegExpRouter.

The code to reproduce it. The server side application:

import { Hono } from 'hono'
import { TrieRouter } from 'hono/router/trie-router'

const wait = async (ms: number) => {
  return new Promise((resolve) => {
    setTimeout(resolve, ms)
  })
}

const app = new Hono({ router: new TrieRouter() })

app.use('*', async (c, next) => {
  await wait(Math.random() * 200)
  return next()
})

app.get('/modules/:id/versions/:version', async (c) => {
  const id = c.req.param('id')
  const version = c.req.param('version')

  console.log('path', c.req.path)
  console.log('version', version)

  return c.json({
    id,
    version,
  })
})

export default app

The client code which makes requests to the server application:

const examples = [
  'http://localhost:8787/modules/first/versions/first',
  'http://localhost:8787/modules/second/versions/second',
  'http://localhost:8787/modules/third/versions/third',
]

const test = () => {
  for (const example of examples) {
    fetch(example)
      .then((response) => response.json())
      .then((data) => {
        const splitted = example.split('/')
        const expected = splitted[splitted.length - 1]

        if (expected !== data.version) {
          console.error(`Error: exprected ${expected} but got ${data.version} - url was ${example}`)
        }
      })
  }
}

test()

The results:

Error: exprected second but got third - url was http://localhost:8787/modules/second/versions/second
Error: exprected first but got third - url was http://localhost:8787/modules/first/versions/first

Patches

"v3.11.7" includes the change to fix this issue.

Workarounds

Don't use TrieRouter directly.

// DON'T USE TrieRouter
import { TrieRouter } from 'hono/router/trie-router'
const app = new Hono({ router: new TrieRouter() })

References

Router options on the Hono website: https://hono.dev/api/hono#router-option

CVE-2024-32869

Summary

When using serveStatic with deno, it is possible to directory traverse where main.ts is located.

My environment is configured as per this tutorial
https://hono.dev/getting-started/deno

PoC

$ tree
.
├── deno.json
├── deno.lock
├── main.ts
├── README.md
└── static
    └── a.txt

source

import { Hono } from 'https://deno.land/x/[email protected]/mod.ts'
import { serveStatic } from 'https://deno.land/x/[email protected]/middleware.ts'

const app = new Hono()
app.use('/static/*', serveStatic({ root: './' }))

Deno.serve(app.fetch)

request

curl localhost:8000/static/%2e%2e/main.ts

response is content of main.ts

Impact

Unexpected files are retrieved.

CVE-2024-43787

Summary

Hono CSRF middleware can be bypassed using crafted Content-Type header.

Details

MIME types are case insensitive, but isRequestedByFormElementRe only matches lower-case.

https://github.com/honojs/hono/blob/b0af71fbcc6dbe44140ea76f16d68dfdb32a99a0/src/middleware/csrf/index.ts#L16-L17

As a result, attacker can bypass csrf middleware using upper-case form-like MIME type, such as "Application/x-www-form-urlencoded".

PoC

<html>
  <head>
    <title>CSRF Test</title>
    <script defer>
      document.addEventListener("DOMContentLoaded", () => {
        document.getElementById("btn").addEventListener("click", async () => {
          const res = await fetch("http://victim.example.com/test", {
            method: "POST",
            credentials: "include",
            headers: {
              "Content-Type": "Application/x-www-form-urlencoded",
            },
          });
        });
      });
    </script>
  </head>
  <body>
    <h1>CSRF Test</h1>
    <button id="btn">Click me!</button>
  </body>
</html>

Impact

Bypass csrf protection implemented with hono csrf middleware.

Discussion

I'm not sure that omitting csrf checks for Simple POST request is a good idea.
CSRF prevention and CORS are different concepts even though CORS can prevent CSRF in some cases.

CVE-2024-48913

Summary

Bypass CSRF Middleware by a request without Content-Type herader.

Details

Although the csrf middleware verifies the Content-Type Header, Hono always considers a request without a Content-Type header to be safe.

https://github.com/honojs/hono/blob/cebf4e87f3984a6a034e60a43f542b4c5225b668/src/middleware/csrf/index.ts#L76-L89

PoC

// server.js
import { Hono } from 'hono'
import { csrf }from 'hono/csrf'
const app = new Hono()
app.use(csrf())
app.get('/', (c) => {
  return c.html('Hello Hono!')
})
app.post('/', async (c) => {
  console.log("executed")
  return c.text( await c.req.text())
})
Deno.serve(app.fetch)
<!-- PoC.html -->
<script>
async function myclick() {
    await fetch("http://evil.example.com", {
    method: "POST",
    credentials: "include",
    body:new Blob([`test`],{}),
    });
}
</script>
<input type="button" onclick="myclick()" value="run" />

Similarly, the fetch API does not add a Content-Type header for requests that do not include a Body.

await fetch("http://localhost:8000", { method: "POST", credentials: "include"});

Impact

Bypass csrf protection implemented with hono csrf middleware.


Release Notes

honojs/hono (hono)

v4.6.5

Compare Source

Security fix for CSRF Protection Middleware

This release includes a security fix for CSRF Protection Middleware. If you are using CSRF Protection Middleware, please upgrade this hono package immediately.

Before this release, a request without a Content-Type header can bypass the protection. This fix does not allow it. See: GHSA-2234-fmw7-43wr

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.6.4...v4.6.5

v4.6.4

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.6.3...v4.6.4

v4.6.3

Compare Source

This release has many new features, but each feature is small, so we've released it as a patch release.

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.6.2...v4.6.3

v4.6.2

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.6.1...v4.6.2

v4.6.1

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.6.0...v4.6.1

v4.6.0

Compare Source

Hono v4.6.0 is now available!

One of the highlights of this release is the Context Storage Middleware. Let's introduce it.

Context Storage Middleware

Many users may have been waiting for this feature. The Context Storage Middleware uses AsyncLocalStorage to allow handling of the current Context object even outside of handlers.

For example, let’s define a Hono app with a variable message: string.

type Env = {
  Variables: {
    message: string
  }
}

const app = new Hono<Env>()

To enable Context Storage Middleware, register contextStorage() as middleware at the top and set the message value.

import { contextStorage } from 'hono/context-storage'

//...

app.use(contextStorage())

app.use(async (c, next) => {
  c.set('message', 'Hello!')
  await next()
})

getContext() returns the current Context object, allowing you to get the value of the message variable outside the handler.

import { getContext } from 'hono/context-storage'

app.get('/', (c) => {
  return c.text(getMessage())
})

// Access the variable outside the handler.
const getMessage = () => {
  return getContext<Env>().var.message
}

In the case of Cloudflare Workers, you can also access the Bindings outside the handler by using this middleware.

type Env = {
  Bindings: {
    KV: KVNamespace
  }
}

const app = new Hono<Env>()

app.use(contextStorage())

const setKV = (value: string) => {
  return getContext<Env>().env.KV.put('key', value)
}

Thanks @​marceloverdijk !

New features

Other changes

New Contributors

Full Changelog: honojs/hono@v4.5.11...v4.6.0

v4.5.11

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.5.10...v4.5.11

v4.5.10

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.5.9...v4.5.10

v4.5.9

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.5.8...v4.5.9

v4.5.8

Compare Source

Security Fix for CSRF Protection Middleware

Before this release, in versions 4.5.7 and below, the CSRF Protection Middleware did not treat requests including Content-Types with uppercase letters (e.g., Application/x-www-form-urlencoded) as potential attacks, allowing them to pass.

This could cause unexpected behavior, leading to a vulnerability. If you are using the CSRF Protection Middleware, please upgrade to version 4.5.8 or higher immediately.

For more details, see the report here: GHSA-rpfr-3m35-5vx5

v4.5.7

Compare Source

What's Changed
New Contributors

Full Changelog: honojs/hono@v4.5.6...v4.5.7

v4.5.6

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.5.5...v4.5.6

v4.5.5

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.5.4...v4.5.5

v4.5.4

Compare Source

What's Changed
New Contributors

Full Changelog: honojs/hono@v4.5.3...v4.5.4

v4.5.3

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.5.2...v4.5.3

v4.5.2

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.5.1...v4.5.2

v4.5.1

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.5.0...v4.5.1

v4.5.0

Compare Source

v4.4.13

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.4.12...v4.4.13

v4.4.12

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.4.11...v4.4.12

v4.4.11

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.4.10...v4.4.11

v4.4.10

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.4.9...v4.4.10

v4.4.9

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.4.8...v4.4.9

v4.4.8

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.4.7...v4.4.8

v4.4.7

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.4.6...v4.4.7

v4.4.6

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.4.5...v4.4.6

v4.4.5

Compare Source

What's Changed

Full Changelog: honojs/hono@v4.4.4...v4.4.5

v4.4.4

Compare Source

What's Changed

New Contributors

Full Changelog: honojs/hono@v4.4.3...v4.4.4

v4.4.3

Compare Source

What's Changed

Copy link
Contributor Author

renovate bot commented Dec 15, 2023

⚠ Artifact update problem

Renovate failed to update an artifact related to this branch. You probably do not want to merge this PR as-is.

♻ Renovate will retry this branch, including artifacts, only when one of the following happens:

  • any of the package files in this branch needs updating, or
  • the branch becomes conflicted, or
  • you click the rebase/retry checkbox if found above, or
  • you rename this PR's title to start with "rebase!" to trigger it manually

The artifact failure details are included below:

File name: pnpm-lock.yaml
 WARN  GET https://registry.npmjs.org/@burnerwah/tsconfig-cloudflare/-/tsconfig-cloudflare-1.0.2.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20221111.1.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@microsoft/eslint-formatter-sarif/-/eslint-formatter-sarif-3.0.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-0.29.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@vitest/ui/-/ui-0.29.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/concurrently/-/concurrently-8.0.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/eslint-plugin-no-secrets/-/eslint-plugin-no-secrets-0.8.9.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/eslint-plugin-optimize-regex/-/eslint-plugin-optimize-regex-1.2.1.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/hono error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/@burnerwah/tsconfig-cloudflare/-/tsconfig-cloudflare-1.0.2.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20221111.1.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@microsoft/eslint-formatter-sarif/-/eslint-formatter-sarif-3.0.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-0.29.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/@vitest/ui/-/ui-0.29.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/concurrently/-/concurrently-8.0.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/eslint-plugin-no-secrets/-/eslint-plugin-no-secrets-0.8.9.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/eslint-plugin-optimize-regex/-/eslint-plugin-optimize-regex-1.2.1.tgz error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/hono error (ERR_INVALID_THIS). Will retry in 1 minute. 1 retries left.
 WARN  GET https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.19.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
undefined
 ERR_INVALID_THIS  Value of "this" must be of type URLSearchParams

TypeError [ERR_INVALID_THIS]: Value of "this" must be of type URLSearchParams
    at Proxy.getAll (node:internal/url:534:13)
    at Proxy.<anonymous> (/opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60565:55)
    at /opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60627:31
    at Array.reduce (<anonymous>)
    at Proxy.raw (/opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60626:33)
    at new Headers (/opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60511:28)
    at getNodeRequestOptions (/opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60860:23)
    at /opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60917:25
    at new Promise (<anonymous>)
    at fetch (/opt/containerbase/tools/pnpm/8.1.1/20.12.2/node_modules/pnpm/dist/pnpm.cjs:60915:14)
 WARN  GET https://registry.npmjs.org/husky/-/husky-8.0.2.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/lint-staged/-/lint-staged-13.1.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/robots-parser/-/robots-parser-3.0.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/vite/-/vite-4.0.3.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/vitest/-/vitest-0.29.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/vitest-environment-miniflare/-/vitest-environment-miniflare-2.11.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/wrangler/-/wrangler-2.6.2.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.
 WARN  GET https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-1.11.0.tgz error (ERR_INVALID_THIS). Will retry in 10 seconds. 2 retries left.

@renovate renovate bot force-pushed the renovate/npm-hono-vulnerability branch from f99ceb4 to b643174 Compare April 23, 2024 17:28
@renovate renovate bot changed the title Update dependency hono to v3 [SECURITY] Update dependency hono to v4 [SECURITY] Apr 23, 2024
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.

0 participants