From 75cce9193d0fa3290804190eebba052f91a66d33 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 08:24:40 +0300 Subject: [PATCH 01/11] Exposed the eop edition through the CRE API endpoint Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/src/domain/cre/creController.ts | 6 ++++-- .../src/routes/api/cre/[edition]/[lang]/+server.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cornucopia.owasp.org/src/domain/cre/creController.ts b/cornucopia.owasp.org/src/domain/cre/creController.ts index bd9d218b0..c0f51b4e6 100644 --- a/cornucopia.owasp.org/src/domain/cre/creController.ts +++ b/cornucopia.owasp.org/src/domain/cre/creController.ts @@ -36,14 +36,16 @@ export class CreController { ['webapp', "OWASP Cornucopia Website App Edition"], ['mobileapp', "OWASP Cornucopia Mobile App Edition"], ['companion', "OWASP Cornucopia Companion Edition"], - ['dbd', "Cornucopia Digital Benefits and Disbenefits Edition"] + ['dbd', "Cornucopia Digital Benefits and Disbenefits Edition"], + ['eop', "Elevation of Privilege Edition"] ]); private static category: Map = new Map([ ['webapp', "Website Application"], ['mobileapp', "Mobile Application"], ['companion', "Companion suits"], - ['dbd', "Digital Benefits and Disbenefits"] + ['dbd', "Digital Benefits and Disbenefits"], + ['eop', "Elevation of Privilege"] ]); constructor(deck: Map, controller: MappingController) { diff --git a/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/+server.ts b/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/+server.ts index 613b62ae3..f0a242aee 100644 --- a/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/+server.ts +++ b/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/+server.ts @@ -11,7 +11,7 @@ const _responseInit: ResponseInit = { }, }; -const editions = ["webapp", "mobileapp", "companion", "dbd"] +const editions = ["webapp", "mobileapp", "companion", "dbd", "eop"] export const GET: RequestHandler = ({ url }) => { const params = url.pathname.split('/'); From a42a372cecc180d22f74af09a5dc7741b9612849 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 13:25:07 +0300 Subject: [PATCH 02/11] Served the Spanish and Russian translations of the eop deck in the API Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/src/domain/suit/suitController.ts | 2 +- cornucopia.owasp.org/src/lib/services/deckService.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cornucopia.owasp.org/src/domain/suit/suitController.ts b/cornucopia.owasp.org/src/domain/suit/suitController.ts index c8335b21b..c428770b7 100644 --- a/cornucopia.owasp.org/src/domain/suit/suitController.ts +++ b/cornucopia.owasp.org/src/domain/suit/suitController.ts @@ -10,7 +10,7 @@ export class SuitController { ['mobileapp', {lang: ['en']}], ['webapp', {lang: ['en', 'es', 'fr', 'nl', 'no_nb', 'pt_br', 'pt_pt', 'ru', 'it']}], ['companion', {lang: ['en']}], - ['eop', {lang: ['en']}] + ['eop', {lang: ['en', 'es', 'ru']}] ]); public static getSuits() : Map diff --git a/cornucopia.owasp.org/src/lib/services/deckService.ts b/cornucopia.owasp.org/src/lib/services/deckService.ts index 77f4d28a9..8fdb2ec8e 100644 --- a/cornucopia.owasp.org/src/lib/services/deckService.ts +++ b/cornucopia.owasp.org/src/lib/services/deckService.ts @@ -18,14 +18,14 @@ export class DeckService { { lang: ['en', 'hi', 'uk'], edition: 'mobileapp', version: '1.1' }, { lang: ['en', 'es', 'fr', 'nl', 'no_nb', 'pt_br', 'pt_pt', 'ru', 'it', 'hi', 'uk'], edition: 'webapp', version: '3.0' }, { lang: ['en'], edition: 'companion', version: '1.0' }, - { lang: ['en'], edition: 'eop', version: '5.0' } + { lang: ['en', 'es', 'ru'], edition: 'eop', version: '5.0' } ]; private static readonly decks: Deck[] = [ { edition: 'mobileapp', version: '1.1', lang: ['en', 'hi', 'uk'] }, { edition: 'webapp', version: '3.0', lang: ['en', 'es', 'fr', 'nl', 'no_nb', 'pt_br', 'pt_pt', 'ru', 'it', 'hi', 'uk'] }, { edition: 'webapp', version: '2.2', lang: ['en', 'es', 'fr', 'nl', 'no_nb', 'pt_br', 'pt_pt', 'ru', 'it'] }, { edition: 'companion', version: '1.0', lang: ['en'] }, - { edition: 'eop', version: '5.0', lang: ['en'] }, + { edition: 'eop', version: '5.0', lang: ['en', 'es', 'ru'] }, { edition: 'dbd', version: '1.0', lang: ['en'] } ]; From d8dfc7c2b26ca5d21c4bbdef960a3b4393f6da34 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 14:16:02 +0300 Subject: [PATCH 03/11] Updated the documentation description string Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/static/api/openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cornucopia.owasp.org/static/api/openapi.yaml b/cornucopia.owasp.org/static/api/openapi.yaml index d504907af..009c227aa 100644 --- a/cornucopia.owasp.org/static/api/openapi.yaml +++ b/cornucopia.owasp.org/static/api/openapi.yaml @@ -4,8 +4,8 @@ info: title: OWASP Cornucopia API description: | Public API for accessing OWASP Cornucopia card data and metadata. - This API exposes language metadata and Open CRE mappings - for both Website App and Mobile App editions. + This API exposes language metadata, card mappings and Open CRE mappings + for the Cornucopia editions and the Elevation of Privilege edition. version: 1.0.0 servers: From 6a319aa112d5b7a479275415ad7823b9bb8d7842 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 14:19:58 +0300 Subject: [PATCH 04/11] Fixed identation of LanguageMetaCompanion schema definition \and added schema for LanguageMetaEop Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/static/api/openapi.yaml | 63 +++++++++++++------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/cornucopia.owasp.org/static/api/openapi.yaml b/cornucopia.owasp.org/static/api/openapi.yaml index 009c227aa..cb095fba1 100644 --- a/cornucopia.owasp.org/static/api/openapi.yaml +++ b/cornucopia.owasp.org/static/api/openapi.yaml @@ -595,26 +595,47 @@ components: version: type: string example: "1.0" -LanguageMetaCompanion: + LanguageMetaCompanion: + type: object + properties: + meta: type: object properties: - meta: - type: object - properties: - edition: - type: string - example: OWASP Cornucopia Companion Edition - component: - type: string - example: cards - language: - type: string - example: all - languages: - type: array - items: - type: string - example: [en] - version: - type: string - example: "1.0" + edition: + type: string + example: OWASP Cornucopia Companion Edition + component: + type: string + example: cards + language: + type: string + example: all + languages: + type: array + items: + type: string + example: [en] + version: + type: string + example: "1.0" + + LanguageMetaEop: + type: object + properties: + meta: + type: object + properties: + component: + type: string + example: cards + language: + type: string + example: all + languages: + type: array + items: + type: string + example: [en, es, ru] + version: + type: string + example: "5.0" From 643cc6aea5f9de2703d13ac53649e68a745710a4 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 14:23:15 +0300 Subject: [PATCH 05/11] Added '/lang/eop/{version}' to the doc endpoints to provide information about supported languages for the EoP edition. Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/static/api/openapi.yaml | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cornucopia.owasp.org/static/api/openapi.yaml b/cornucopia.owasp.org/static/api/openapi.yaml index cb095fba1..be390c9af 100644 --- a/cornucopia.owasp.org/static/api/openapi.yaml +++ b/cornucopia.owasp.org/static/api/openapi.yaml @@ -106,6 +106,36 @@ paths: languages: [en] version: "1.0" + /lang/eop/{version}: + get: + summary: Get supported languages for Elevation of Privilege edition + description: | + Returns metadata about supported languages for the + Elevation of Privilege Edition. + parameters: + - name: version + in: path + required: true + schema: + type: string + enum: ["5.0"] + responses: + '200': + description: Language metadata for Elevation of Privilege edition + content: + application/json: + schema: + $ref: '#/components/schemas/LanguageMetaEop' + examples: + example: + summary: Example language metadata response + value: + meta: + component: cards + language: all + languages: [en, es, ru] + version: "5.0" + /cre/dbd/{lang}: get: summary: Get DBD cards by language From 83a823373477a15b8b1f12eadf834a3db8f7ff17 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 14:52:54 +0300 Subject: [PATCH 06/11] Added '/mapping/eop/{version}' to the doc endpoints Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/static/api/openapi.yaml | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/cornucopia.owasp.org/static/api/openapi.yaml b/cornucopia.owasp.org/static/api/openapi.yaml index be390c9af..2b8b2bc5f 100644 --- a/cornucopia.owasp.org/static/api/openapi.yaml +++ b/cornucopia.owasp.org/static/api/openapi.yaml @@ -398,6 +398,43 @@ paths: capec: [ 508 ] safecode: [ "-" ] + /mapping/eop/{version}: + get: + summary: Get Elevation of Privilege mapping by version + description: | + Get the Elevation of Privilege Edition mapping data + by version. Each card just maps to its STRIDE category. + parameters: + - name: version + in: path + required: true + schema: + type: string + enum: ["5.0"] + responses: + '200': + description: Elevation of Privilege mapping data + content: + application/json: + schema: + type: object + examples: + example: + summary: Example Elevation of Privilege mapping response + value: + meta: + edition: eop + component: mappings + language: ALL + version: "5.0" + cards: + SP2: + id: "SP2" + value: "2" + url: "https://cornucopia.owasp.org/cards/SP2" + stride: [ S ] + stride_print: [ Spoofing ] + /cre/mobileapp/{lang}: get: summary: Get Mobile cards by language From d837d966c91611746fb5dddb16e2f59c2a725bd8 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 14:55:37 +0300 Subject: [PATCH 07/11] Added '/cre/eop/{lang}' to the doc endpoints Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/static/api/openapi.yaml | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/cornucopia.owasp.org/static/api/openapi.yaml b/cornucopia.owasp.org/static/api/openapi.yaml index 2b8b2bc5f..d65bfa6db 100644 --- a/cornucopia.owasp.org/static/api/openapi.yaml +++ b/cornucopia.owasp.org/static/api/openapi.yaml @@ -527,6 +527,48 @@ paths: version: "1.0" standards: [] + /cre/eop/{lang}: + get: + summary: Get Elevation of Privilege cards by language + description: | + Get the Elevation of Privilege Edition cards by language. + This edition does not have Open CRE mappings, so the links + array of each card is empty. + parameters: + - name: lang + in: path + required: true + schema: + type: string + enum: [en, es, ru] + responses: + '200': + description: Elevation of Privilege cards + content: + application/json: + schema: + type: object + examples: + example: + summary: Example Elevation of Privilege response + value: + meta: + edition: Elevation of Privilege Edition + component: cards + language: en + version: "5.0" + standards: + - doctype: Tool + id: https://cornucopia.owasp.org/edition/eop/SP2/5.0/en + name: Elevation of Privilege Edition + section: Spoofing + description: An attacker could take over the port or socket that the server normally uses + sectionID: SP2 + hyperlink: https://cornucopia.owasp.org/edition/eop/SP2/5.0/en + links: [] + tags: [Threat modeling, Elevation of Privilege] + tooltype: Defensive + /lang/{edition}/{version}: get: summary: Get language metadata for an edition version From 5d9c4f2fdd75ef16014cd86a826fd63e84104738 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 15:15:38 +0300 Subject: [PATCH 08/11] Extended '/lang/{edition}/{version}' doc endpoint to provide the EoP edition Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/static/api/openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cornucopia.owasp.org/static/api/openapi.yaml b/cornucopia.owasp.org/static/api/openapi.yaml index d65bfa6db..74ecc9c91 100644 --- a/cornucopia.owasp.org/static/api/openapi.yaml +++ b/cornucopia.owasp.org/static/api/openapi.yaml @@ -574,14 +574,14 @@ paths: summary: Get language metadata for an edition version description: | Returns the list of supported languages for a given edition and version. - Works for all registered editions (webapp, mobileapp, companion). + Works for all registered editions (webapp, mobileapp, companion, eop). parameters: - name: edition in: path required: true schema: type: string - enum: [webapp, mobileapp, companion] + enum: [webapp, mobileapp, companion, eop] - name: version in: path required: true From 2e56b664141251b6b53a39363963a5014ae6f4f7 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 15:24:35 +0300 Subject: [PATCH 09/11] Added a test for the eop languages endpoint Signed-off-by: Ayman Algamal --- .../lang/[edition]/[version]/server.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/cornucopia.owasp.org/src/routes/api/lang/[edition]/[version]/server.test.ts b/cornucopia.owasp.org/src/routes/api/lang/[edition]/[version]/server.test.ts index 810b71806..3748a5808 100644 --- a/cornucopia.owasp.org/src/routes/api/lang/[edition]/[version]/server.test.ts +++ b/cornucopia.owasp.org/src/routes/api/lang/[edition]/[version]/server.test.ts @@ -34,6 +34,29 @@ describe('GET /api/lang/[edition]/[version]', () => { }); }); + it('returns languages for the eop edition and version', async () => { + vi.spyOn(DeckService, 'hasEdition').mockReturnValue(true); + vi.spyOn(DeckService, 'hasVersion').mockReturnValue(true); + vi.spyOn(DeckService, 'getLanguagesForEditionVersion').mockReturnValue(['en', 'es', 'ru']); + + const response = await GET({ + params: { edition: 'eop', version: '5.0' } + } as unknown); + + expect(response.status).toBe(200); + expect(response.headers.get('content-type')).toContain('application/json'); + + const body = await response.json(); + expect(body).toEqual({ + meta: { + component: 'cards', + language: 'all', + languages: ['en', 'es', 'ru'], + version: '5.0' + } + }); + }); + it('throws 404 when edition is invalid', () => { vi.spyOn(DeckService, 'hasEdition').mockReturnValue(false); vi.spyOn(DeckService, 'getLatestEditions').mockReturnValue(['webapp', 'mobileapp']); From 971649e679562e6f5f0a1083058b0550fc4992ef Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 15:24:38 +0300 Subject: [PATCH 10/11] Added a test for the eop CRE endpoint Signed-off-by: Ayman Algamal --- .../api/cre/[edition]/[lang]/server.test.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts b/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts index 46033bd72..49460b62d 100644 --- a/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts +++ b/cornucopia.owasp.org/src/routes/api/cre/[edition]/[lang]/server.test.ts @@ -119,6 +119,38 @@ describe('GET /api/cre/[edition]/[lang]', () => { + it('returns valid CRE mapping response for eop', () => { + vi.spyOn(DeckService, 'getLatestVersion').mockReturnValue('5.0'); + + vi.spyOn(DeckService.prototype, 'getCardDataForEditionVersionLang') + .mockReturnValue(new Map([ + ['SP2', { + id: 'SP2', + edition: 'eop', + url: '/cards/SP2', + suitNameLocal: 'Spoofing', + desc: 'Spoofing threat' + }] + ]) as any); + + vi.spyOn(MappingService.prototype, 'getCardMappingForLatestEdtions') + .mockReturnValue(new Map([ + ['eop', { + meta: { version: '5.0' }, + suits: [{ + cards: [{ + id: 'SP2', + stride: ['S'] + }] + }] + }] + ]) as any); + + const response = GET({ url: new URL('http://localhost/api/cre/eop/en') } as any); + + expect(response).toBeDefined(); + }); + it('falls back to webapp and en defaults when url has no path segments', () => { vi.spyOn(DeckService, 'getLanguages').mockReturnValue(['en']); vi.spyOn(DeckService, 'getLatestVersion').mockReturnValue('3.0'); From b73367789a02d87f44482dc25f803d0dd078f319 Mon Sep 17 00:00:00 2001 From: Ayman Algamal Date: Sun, 19 Jul 2026 15:24:41 +0300 Subject: [PATCH 11/11] Updated deck service tests to cover the eop languages Signed-off-by: Ayman Algamal --- cornucopia.owasp.org/src/lib/services/deckService.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cornucopia.owasp.org/src/lib/services/deckService.test.ts b/cornucopia.owasp.org/src/lib/services/deckService.test.ts index 9c8c6c2ed..43b39731f 100644 --- a/cornucopia.owasp.org/src/lib/services/deckService.test.ts +++ b/cornucopia.owasp.org/src/lib/services/deckService.test.ts @@ -144,7 +144,7 @@ describe('DeckService tests', () => { expect(decks).toHaveLength(6); expect(decks).toContainEqual({ edition: 'mobileapp', version: '1.1', lang: ['en', 'hi', 'uk'] }); expect(decks).toContainEqual({ edition: 'companion', version: '1.0', lang: ['en'] }); - expect(decks).toContainEqual({ edition: 'eop', version: '5.0', lang: ['en'] }); + expect(decks).toContainEqual({ edition: 'eop', version: '5.0', lang: ['en', 'es', 'ru'] }); expect(decks).toContainEqual({ edition: 'dbd', version: '1.0', lang: ['en'] }); expect(decks).toContainEqual({ edition: 'webapp', @@ -248,9 +248,9 @@ describe('DeckService tests', () => { expect(languages).toEqual(['en']); }); - it('should return only en for eop version 5.0', () => { + it('should return all supported languages for eop version 5.0', () => { const languages = DeckService.getLanguagesForEditionVersion('eop', '5.0'); - expect(languages).toEqual(['en']); + expect(languages).toEqual(['en', 'es', 'ru']); }); it('should return empty array for unknown version', () => {