Skip to content
Merged
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
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,4 @@ Non-human employees are becoming the future of cybersecurity, and enterprises ne

</div>

⏰ Not posting time (current: 2h UTC, scheduled: 7h UTC)

✅ Aggregation complete!
25 changes: 20 additions & 5 deletions portfolio.html
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@
gtag('js', new Date());
gtag('config', 'G-LWN1RSPQMJ');
</script>

<!-- DOMPurify for XSS protection -->
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a version mismatch between the DOMPurify CDN version (3.0.8) being loaded and the package.json dependency version (3.3.1). This inconsistency could lead to unexpected behavior or missing security patches. Consider updating the CDN URL to use version 3.3.1 or use a caret/tilde version specifier to automatically get the latest patch version.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.3.1/dist/purify.min.js"></script>

Copilot uses AI. Check for mistakes.
</head>
<body>
<!-- Hero Section -->
Expand Down Expand Up @@ -521,11 +524,23 @@ <h2 class="section-title">
const card = document.createElement('div');
card.className = 'project-card';

// Sanitize strings to prevent XSS
const name = escapeHtml(repo.name || 'Untitled');
const description = escapeHtml(repo.description || 'No description available');
const language = escapeHtml(repo.language || 'Unknown');
const url = escapeHtml(repo.html_url || '#');
// Sanitize strings to prevent XSS using DOMPurify
const name = DOMPurify.sanitize(repo.name || 'Untitled');
const description = DOMPurify.sanitize(repo.description || 'No description available');
const language = DOMPurify.sanitize(repo.language || 'Unknown');

// Validate URL scheme
let url = '#';
if (repo.html_url) {
try {
const urlObj = new URL(repo.html_url);
if (urlObj.protocol === 'http:' || urlObj.protocol === 'https:') {
url = DOMPurify.sanitize(repo.html_url);
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sanitizing URLs with DOMPurify.sanitize is ineffective for URL validation. DOMPurify is designed to sanitize HTML content, not validate URL schemes. The URL has already been validated by the URL constructor check above. Instead, use the validated URL object's href property directly, or simply use repo.html_url after successful validation without DOMPurify sanitization.

Suggested change
url = DOMPurify.sanitize(repo.html_url);
url = urlObj.href;

Copilot uses AI. Check for mistakes.
}
} catch (_) {
url = '#';
}
}

card.innerHTML = `
<div class="project-header">
Expand Down
26 changes: 22 additions & 4 deletions reader.html
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@
gtag('js', new Date());
gtag('config', 'G-LWN1RSPQMJ');
</script>

<!-- DOMPurify for XSS protection -->
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a version mismatch between the DOMPurify CDN version (3.0.8) being loaded and the package.json dependency version (3.3.1). This inconsistency could lead to unexpected behavior or missing security patches. Consider updating the CDN URL to use version 3.3.1 or use a caret/tilde version specifier to automatically get the latest patch version.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.3.1/dist/purify.min.js"></script>

Copilot uses AI. Check for mistakes.
</head>
<body>
<!-- Header -->
Expand Down Expand Up @@ -442,8 +445,19 @@ <h2>Impossible de charger l'article</h2>
const articleSource = params.get('source');
const articleTags = params.get('tags');

// If article parameters exist, show article view
if (articleUrl) {
// Validate URL scheme to prevent XSS
function isValidHttpUrl(string) {
if (!string) return false;
try {
const url = new URL(string);
return url.protocol === 'http:' || url.protocol === 'https:';
} catch (_) {
return false;
}
}

// If article parameters exist and URL is valid, show article view
if (articleUrl && isValidHttpUrl(articleUrl)) {
Comment on lines +448 to +460
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL validation logic only checks for http: and https: protocols, but does not protect against other XSS vectors. While the validation prevents javascript: URLs from being used, the validated articleUrl is still used directly in href and iframe.src assignments (lines 488-489, 496) without further sanitization. The validation should be followed by using the validated URL object's href property to ensure the URL is properly normalized.

Copilot uses AI. Check for mistakes.
showView('article');

// Show article tab and external link button
Expand All @@ -457,12 +471,16 @@ <h2>Impossible de charger l'article</h2>
}

if (articleSource) {
document.getElementById('articleSource').innerHTML = `📰 <strong>${decodeURIComponent(articleSource)}</strong>`;
const sanitizedSource = DOMPurify.sanitize(decodeURIComponent(articleSource));
document.getElementById('articleSource').innerHTML = `📰 <strong>${sanitizedSource}</strong>`;
}

if (articleTags) {
const tags = decodeURIComponent(articleTags).split(',');
const tagsHtml = tags.map(tag => `<span class="tag">${tag.trim()}</span>`).join('');
const tagsHtml = tags.map(tag => {
const sanitizedTag = DOMPurify.sanitize(tag.trim());
return `<span class="tag">${sanitizedTag}</span>`;
}).join('');
document.getElementById('articleTags').innerHTML = tagsHtml;
}

Expand Down
12 changes: 9 additions & 3 deletions stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@
gtag('js', new Date());
gtag('config', 'G-LWN1RSPQMJ');
</script>

<!-- DOMPurify for XSS protection -->
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a version mismatch between the DOMPurify CDN version (3.0.8) being loaded and the package.json dependency version (3.3.1). This inconsistency could lead to unexpected behavior or missing security patches. Consider updating the CDN URL to use version 3.3.1 or use a caret/tilde version specifier to automatically get the latest patch version.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.3.1/dist/purify.min.js"></script>

Copilot uses AI. Check for mistakes.
</head>
<body>
<div class="container">
Expand Down Expand Up @@ -401,10 +404,11 @@ <h1>
let html = '';
sorted.forEach(([label, value]) => {
const percentage = (value / maxValue) * 100;
const sanitizedLabel = DOMPurify.sanitize(label);
html += `
<div class="chart-bar-container">
<div class="chart-bar-label">
<span class="chart-bar-label-name">${label}</span>
<span class="chart-bar-label-name">${sanitizedLabel}</span>
<span class="chart-bar-label-value">${value}</span>
</div>
<div class="chart-bar-bg">
Expand All @@ -429,11 +433,13 @@ <h1>

let html = '';
articles.forEach((article, index) => {
const sanitizedTitle = DOMPurify.sanitize(article.title);
const sanitizedSource = DOMPurify.sanitize(article.source);
html += `
<li class="article-item">
<div class="article-info">
<div class="article-title-stat">${index + 1}. ${article.title}</div>
<div class="article-source">Source: ${article.source}</div>
<div class="article-title-stat">${index + 1}. ${sanitizedTitle}</div>
<div class="article-source">Source: ${sanitizedSource}</div>
</div>
<div class="article-clicks">${article.clicks}</div>
</li>
Expand Down
Loading