VYPR
Critical severityNVD Advisory· Published Mar 2, 2021· Updated Aug 3, 2024

Prefix escape

CVE-2021-21321

Description

fastify-reply-from is an npm package which is a fastify plugin to forward the current http request to another server. In fastify-reply-from before version 4.0.2, by crafting a specific URL, it is possible to escape the prefix of the proxied backend service. If the base url of the proxied server is "/pub/", a user expect that accessing "/priv" on the target service would not be possible. In affected versions, it is possible. This is fixed in version 4.0.2.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
fastify-reply-fromnpm
< 4.0.24.0.2

Affected products

1

Patches

1
dea227dda606

Merge pull request from GHSA-qmw8-3v4g-gwj4

https://github.com/fastify/fastify-reply-fromMatteo CollinaFeb 19, 2021via ghsa
3 files changed · +32 7
  • lib/utils.js+8 2 modified
    @@ -59,8 +59,14 @@ function buildURL (source, reqBase) {
       const dest = new URL(source, reqBase)
     
       // if base is specified, source url should not override it
    -  if (reqBase && !reqBase.startsWith(dest.origin)) {
    -    throw new Error('source must be a relative path string')
    +  if (reqBase) {
    +    if (!reqBase.endsWith('/') && dest.href.length > reqBase.length) {
    +      reqBase = reqBase + '/'
    +    }
    +
    +    if (!dest.href.startsWith(reqBase)) {
    +      throw new Error('source must be a relative path string')
    +    }
       }
     
       return dest
    
  • test/build-url.js+19 1 modified
    @@ -21,13 +21,31 @@ test('should return same source when base is not specified', (t) => {
       t.equal(url.href, 'http://localhost/hi')
     })
     
    +test('should handle lack of trailing slash in base', (t) => {
    +  t.plan(3)
    +  let url = buildURL('hi', 'http://localhost/hi')
    +  t.equal(url.href, 'http://localhost/hi')
    +
    +  url = buildURL('hi/', 'http://localhost/hi')
    +  t.equal(url.href, 'http://localhost/hi/')
    +
    +  url = buildURL('hi/more', 'http://localhost/hi')
    +  t.equal(url.href, 'http://localhost/hi/more')
    +})
    +
     const errorInputs = [
       { source: '//10.0.0.10/hi', base: 'http://localhost' },
       { source: 'http://10.0.0.10/hi', base: 'http://localhost' },
       { source: 'https://10.0.0.10/hi', base: 'http://localhost' },
       { source: 'blah://10.0.0.10/hi', base: 'http://localhost' },
       { source: '//httpbin.org/hi', base: 'http://localhost' },
    -  { source: 'urn:foo:bar', base: 'http://localhost' }
    +  { source: 'urn:foo:bar', base: 'http://localhost' },
    +  { source: 'http://localhost/private', base: 'http://localhost/exposed/' },
    +  { source: 'http://localhost/exposed-extra', base: 'http://localhost/exposed' },
    +  { source: '/private', base: 'http://localhost/exposed/' },
    +  { source: '/exposed-extra', base: 'http://localhost/exposed' },
    +  { source: '../private', base: 'http://localhost/exposed/' },
    +  { source: 'exposed-extra', base: 'http://localhost/exposed' }
     ]
     
     test('should throw when trying to override base', (t) => {
    
  • test/unix-http.js+5 4 modified
    @@ -13,14 +13,15 @@ if (process.platform === 'win32') {
       process.exit(0)
     }
     
    +const socketPath = `${__filename}.socket`
    +const upstream = `unix+http://${querystring.escape(socketPath)}/`
    +
     const instance = Fastify()
    -instance.register(From)
    +instance.register(From, { base: upstream })
     
     t.plan(10)
     t.tearDown(instance.close.bind(instance))
     
    -const socketPath = `${__filename}.socket`
    -
     try {
       fs.unlinkSync(socketPath)
     } catch (_) {
    @@ -37,7 +38,7 @@ const target = http.createServer((req, res) => {
     })
     
     instance.get('/', (request, reply) => {
    -  reply.from(`unix+http://${querystring.escape(socketPath)}/hello`)
    +  reply.from('hello')
     })
     
     t.tearDown(target.close.bind(target))
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.