VYPR
Medium severity6.5OSV Advisory· Published Aug 20, 2025· Updated Apr 15, 2026

CVE-2025-50864

CVE-2025-50864

Description

An Origin Validation Error in the elysia-cors library thru 1.3.0 allows attackers to bypass Cross-Origin Resource Sharing (CORS) restrictions. The library incorrectly validates the supplied origin by checking if it is a substring of any domain in the site's CORS policy, rather than performing an exact match. For example, a malicious origin like "notexample.com", "example.common.net" is whitelisted when the site's CORS policy specifies "example.com." This vulnerability enables unauthorized access to user data on sites using the elysia-cors library for CORS validation.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@elysiajs/corsnpm
< 1.3.11.3.1

Affected products

1

Patches

1
9b9eb92e32a7

:wrench: fix: strictly check origin not using sub includes

https://github.com/elysiajs/elysia-corssaltyaomMay 8, 2025via ghsa
5 files changed · +161 141
  • CHANGELOG.md+3 1 modified
    @@ -1,9 +1,11 @@
    +# 1.3.1 - 8 May 2025
    +Bug fix:
    +- strictly check origin not using sub includes
     
     # 1.3.0-exp.0 - 23 Apr 2025
     Change:
     - Add support for Elysia 1.3
     
    -
     # 1.2.0-rc.0 - 23 Dec 2024
     Change:
     - Add support for Elysia 1.2
    
  • example/index.ts+15 16 modified
    @@ -1,21 +1,20 @@
     import { Elysia, t } from 'elysia'
     import { cors } from '../src/index'
     
    -new Elysia()
    -	.use(cors())
    +const app = new Elysia()
    +	.use(
    +		cors({
    +			origin: 'example.com'
    +		})
    +	)
     	.post('/', ({ body }) => body)
    -	.listen(3000)
     
    -new Elysia().get('/', () => 'hi').listen(3001)
    -
    -// app.handle(
    -//     new Request('http://localhost/awd', {
    -//         headers: {
    -//             origin: 'https://saltyaom.com'
    -//         }
    -//     })
    -// )
    -//     .then((x) => x.headers.toJSON())
    -//     .then(console.log)
    -
    -// export type App = typeof app
    +app.handle(
    +	new Request('http://localhost/awd', {
    +		headers: {
    +			origin: 'http://notexample.com'
    +		}
    +	})
    +)
    +	.then((x) => x.headers.toJSON())
    +	.then(console.log)
    
  • package.json+2 2 modified
    @@ -1,6 +1,6 @@
     {
         "name": "@elysiajs/cors",
    -    "version": "1.3.0",
    +    "version": "1.3.1",
         "description": "Plugin for Elysia that for Cross Origin Requests (CORs)",
         "author": {
             "name": "saltyAom",
    @@ -46,4 +46,4 @@
         "peerDependencies": {
             "elysia": ">= 1.3.0"
         }
    -}
    \ No newline at end of file
    +}
    
  • src/index.ts+2 1 modified
    @@ -191,7 +191,8 @@ const processOrigin = (
     
     	switch (typeof origin) {
     		case 'string':
    -			if (origin.indexOf('://') === -1) return from.includes(origin)
    +			const fromProtocol = from.indexOf('://')
    +			if (fromProtocol !== -1) from = from.slice(fromProtocol + 3)
     
     			return origin === from
     
    
  • test/origin.test.ts+139 121 modified
    @@ -5,125 +5,143 @@ import { describe, expect, it } from 'bun:test'
     import { req } from './utils'
     
     describe('Origin', () => {
    -    it('Accept string', async () => {
    -        const app = new Elysia()
    -            .use(
    -                cors({
    -                    origin: 'saltyaom.com'
    -                })
    -            )
    -            .get('/', () => 'A')
    -
    -        const res = await app.fetch(
    -            new Request('http://localhost/', {
    -                headers: {
    -                    origin: 'https://saltyaom.com'
    -                }
    -            })
    -        )
    -
    -        expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    -            'https://saltyaom.com'
    -        )
    -    })
    -
    -    it('Accept boolean', async () => {
    -        const app = new Elysia()
    -            .use(
    -                cors({
    -                    origin: true
    -                })
    -            )
    -            .get('/', () => 'HI')
    -
    -        const res = await app.handle(req('/'))
    -        expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    -            '*'
    -        )
    -    })
    -
    -    it('Accept RegExp', async () => {
    -        const app = new Elysia()
    -            .use(
    -                cors({
    -                    origin: /\.com/g
    -                })
    -            )
    -            .get('/', () => 'HI')
    -
    -        const notAllowed = await app.handle(
    -            req('/', {
    -                Origin: 'https://example.org'
    -            })
    -        )
    -        const allowed = await app.handle(
    -            req('/', {
    -                Origin: 'https://example.com'
    -            })
    -        )
    -        expect(notAllowed.headers.get('Access-Control-Allow-Origin')).toBe(null)
    -        expect(allowed.headers.get('Access-Control-Allow-Origin')).toBe(
    -            'https://example.com'
    -        )
    -    })
    -
    -    it('Accept Function', async () => {
    -        const app = new Elysia()
    -            .use(
    -                cors({
    -                    origin: () => true
    -                })
    -            )
    -            .get('/', () => 'HI')
    -
    -        const res = await app.handle(
    -            req('/', {
    -                Origin: 'https://example.com'
    -            })
    -        )
    -        expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    -            'https://example.com'
    -        )
    -    })
    -
    -    it('Accept string[]', async () => {
    -        const app = new Elysia()
    -            .use(
    -                cors({
    -                    origin: ['gehenna.sh', 'saltyaom.com']
    -                })
    -            )
    -            .get('/', () => 'A')
    -
    -        const res = await app.fetch(
    -            new Request('http://localhost/', {
    -                headers: {
    -                    origin: 'https://saltyaom.com'
    -                }
    -            })
    -        )
    -
    -        expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    -            'https://saltyaom.com'
    -        )
    -    })
    -
    -    it('Accept Function[]', async () => {
    -        const app = new Elysia()
    -            .use(
    -                cors({
    -                    origin: ['https://demo.app', () => false, /.com/g]
    -                })
    -            )
    -            .get('/', () => 'HI')
    -
    -        const res = await app.handle(
    -            req('/', {
    -                Origin: 'https://example.com'
    -            })
    -        )
    -        expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    -            'https://example.com'
    -        )
    -    })
    +	it('Accept string', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: 'saltyaom.com'
    +				})
    +			)
    +			.get('/', () => 'A')
    +
    +		const res = await app.fetch(
    +			new Request('http://localhost/', {
    +				headers: {
    +					origin: 'https://saltyaom.com'
    +				}
    +			})
    +		)
    +
    +		expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    +			'https://saltyaom.com'
    +		)
    +	})
    +
    +	it('Accept boolean', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: true
    +				})
    +			)
    +			.get('/', () => 'HI')
    +
    +		const res = await app.handle(req('/'))
    +		expect(res.headers.get('Access-Control-Allow-Origin')).toBe('*')
    +	})
    +
    +	it('Accept RegExp', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: /\.com/g
    +				})
    +			)
    +			.get('/', () => 'HI')
    +
    +		const notAllowed = await app.handle(
    +			req('/', {
    +				Origin: 'https://example.org'
    +			})
    +		)
    +		const allowed = await app.handle(
    +			req('/', {
    +				Origin: 'https://example.com'
    +			})
    +		)
    +		expect(notAllowed.headers.get('Access-Control-Allow-Origin')).toBe(null)
    +		expect(allowed.headers.get('Access-Control-Allow-Origin')).toBe(
    +			'https://example.com'
    +		)
    +	})
    +
    +	it('Accept Function', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: () => true
    +				})
    +			)
    +			.get('/', () => 'HI')
    +
    +		const res = await app.handle(
    +			req('/', {
    +				Origin: 'https://example.com'
    +			})
    +		)
    +		expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    +			'https://example.com'
    +		)
    +	})
    +
    +	it('Accept string[]', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: ['gehenna.sh', 'saltyaom.com']
    +				})
    +			)
    +			.get('/', () => 'A')
    +
    +		const res = await app.fetch(
    +			new Request('http://localhost/', {
    +				headers: {
    +					origin: 'https://saltyaom.com'
    +				}
    +			})
    +		)
    +
    +		expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    +			'https://saltyaom.com'
    +		)
    +	})
    +
    +	it('Accept Function[]', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: ['https://demo.app', () => false, /.com/g]
    +				})
    +			)
    +			.get('/', () => 'HI')
    +
    +		const res = await app.handle(
    +			req('/', {
    +				Origin: 'https://example.com'
    +			})
    +		)
    +		expect(res.headers.get('Access-Control-Allow-Origin')).toBe(
    +			'https://example.com'
    +		)
    +	})
    +
    +	it('strictly check origin not using sub includes', async () => {
    +		const app = new Elysia()
    +			.use(
    +				cors({
    +					origin: 'example.com'
    +				})
    +			)
    +			.post('/', ({ body }) => body)
    +
    +		const response = await app.handle(
    +			new Request('http://localhost/awd', {
    +				headers: {
    +					origin: 'http://notexample.com'
    +				}
    +			})
    +		)
    +
    +		expect(response.headers.has('access-control-allow-origin')).toBeFalse()
    +	})
     })
    

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

7

News mentions

0

No linked articles in our index yet.