Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
# Security Policy

## Reporting a Vulnerability
Please use the <a href="https://cveform.mitre.org/" target="_blank">CVE Program web forms</a> to report security vulnerabilities for the
<a href="https://www.cve.org" target="_blank">CVE website</a>. Please include vulnerability details, steps to reproduce (e.g., proof-of-concept code,
screenshots) and an assessment of the impact in your report. We appreciate concise and high-quality reports.

## Web Form Submissions

* In the “Select a request type” drop down menu, please select “Other”
* Enter your email address in the space provided
* You may enter a PGP key if you prefer to encrypt your correspondence
* In the “Type of comment” drop down menu, please select “Issue”
* In the textbox labeled “Please provide your question, issue, comment, etc.” please start the message with the following information:
- First Line: “CVE Website Security Anomaly Report”
- Second Line: “Distribution: CVE Website Development Team”
- Third Line: "Description: [Free Text description of the anomaly]”
* Enter the Security code
* Click “Submit Request”
Please use the <a href="https://cveform.mitre.org/" target="_blank">CVE Program Web Forms</a> (choose “General Support”) to report security vulnerabilities for the
<a href="https://www.cve.org" target="_blank">CVE website</a>.

Please include:

* Vulnerability details
* Steps to reproduce (e.g., proof-of-concept code, screenshots)
* An assessment of the impact

We appreciate concise and high-quality reports.

## Scope

Expand All @@ -28,4 +22,4 @@ We will release fixes for verified security vulnerabilities. We expect to publis
<a href="https://github.com/CVEProject/cve-website/security/advisories" target="_blank">security advisories</a>.

## Coordination
We appreciate the opportunity to investigate and develop fixes before public disclosure, following coordinated vulnerability disclosure practices.
We appreciate the opportunity to investigate and develop fixes before public disclosure, following coordinated vulnerability disclosure practices.
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"axios": "^1.13.2",
"buefy": "^3.0.3",
"bulma": "^1.0.4",
"dompurify": "^3.4.16",
"leaflet": "^1.9.4",
"lodash": "^4.17.21",
"pinia": "^3.0.4",
Expand Down
14 changes: 11 additions & 3 deletions src/components/AdpVulnerabilityEnrichment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@
v-if="(container.isCna || container.isCveProgram)
&& container.englishDescription.length">
<h4 class="title is-size-5">Description</h4>
<p class="content cve-x-scroll">
{{container.englishDescription}}
</p>
<div v-if="container.englishDescriptionHtml.length"
class="content cve-x-scroll"
v-html="container.englishDescriptionHtml">
</div>
<p v-else class="content cve-x-scroll cve-plain-description is-family-monospace">{{ container.englishDescription }}</p>
</div>
<div v-if="!container.isCveProgram">
<div id="cve-cwes" v-if="container.cwes.length > 0" class="mt-5">
Expand Down Expand Up @@ -250,6 +252,12 @@ function togglePanel() {
<style scoped lang="scss">
@use 'cveRecord' as *;

// Plain-text descriptions keep the CNA's line breaks and indentation,
// but long lines still wrap.
.cve-plain-description {
white-space: pre-wrap;
}

.cve-accordion-header {
background-color: $theme-color-primary-darker !important;
cursor: pointer;
Expand Down
27 changes: 23 additions & 4 deletions src/models/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import {Product} from "./product"
import type {ProductData} from "./product"
import {decodeBase64, sanitizeHtml} from "../utils/htmlUtils"

export interface ContainerData {
providerMetadata: ProviderMetaData;
Expand Down Expand Up @@ -523,13 +524,31 @@ export class Container {

get englishDescription() {

for (const description of this.descriptions) {
return this.englishDescriptionObject?.value ?? '';
}

get englishDescriptionHtml() {

// Returns the sanitized "text/html" supporting media of the English description,
// or an empty string if the CNA did not provide one.

const media = this.englishDescriptionObject?.supportingMedia
?.find(m => m.type.split(';')[0].trim().toLowerCase() === 'text/html');

if (description.lang.toLowerCase().startsWith('en'))
return description.value;
if (!media?.value)
return '';

try {
return sanitizeHtml(media.base64 ? decodeBase64(media.value) : media.value);
} catch {
return '';
}
}

get englishDescriptionObject(): Description | undefined {

return '';
return this.descriptions.find(
description => description.lang.toLowerCase().startsWith('en'));
}

get isAdp() {
Expand Down
2 changes: 1 addition & 1 deletion src/stores/cveListSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export const useCveListSearchStore = defineStore('cveListSearch ', {
},
async getSearchResults() {
this.isQueryingSearchService = true;
const searchUrl = `${import.meta.env.VITE_API_BASE_URL}${import.meta.env.VITE_LIST_SEARCH_PATH}`;
const searchUrl = 'https://dev.search.cve.org/webSearch';

this.resetResults();

Expand Down
48 changes: 48 additions & 0 deletions src/utils/htmlUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import DOMPurify, { type Config } from 'dompurify';

// Elements allowed in HTML supplied by CNAs.
//
// Only text formatting, lists, tables and links are kept.
// Anything that could load external resources, run scripts,
// submit data or restyle the page is removed.

const ALLOWED_TAGS = [
'a', 'abbr', 'b', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd',
'del', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'hr', 'i', 'ins', 'kbd', 'li', 'mark', 'ol', 'p', 'pre', 'q', 's', 'samp',
'small', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot',
'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var'
];

const ALLOWED_ATTR = ['href', 'title', 'colspan', 'rowspan', 'start', 'type'];

const SANITIZE_CONFIG: Config = {
ALLOWED_TAGS,
ALLOWED_ATTR,
ALLOW_DATA_ATTR: false,
};

DOMPurify.addHook('afterSanitizeAttributes', (node) => {

// Links supplied by third parties always open in a new tab
// and must not give the target page access to this window
// or pass referrer information.

if (node.tagName === 'A' && node.hasAttribute('href')) {
node.setAttribute('target', '_blank');
node.setAttribute('rel', 'noopener noreferrer nofollow');
}
});

export function sanitizeHtml(html: string): string {

return DOMPurify.sanitize(html, SANITIZE_CONFIG);
}

export function decodeBase64(value: string): string {

// Decodes a base64-encoded UTF-8 string.

const bytes = Uint8Array.from(atob(value), c => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
}