` has `markdown="1"`
+2. When in doubt, keep content in Markdown outside wrappers, or use pure HTML within wrappers
+3. Test mentally: would Kramdown render this correctly?
+
+## Design Output Format
+
+When proposing or implementing UI changes, structure your response as:
+
+### 1. UX Rationale
+Explain *why* this change improves usability. Reference design principles where relevant.
+
+### 2. Layout Description
+Describe the structure and visual hierarchy of the proposed change.
+
+### 3. Code Implementation
+Provide the complete updated code with appropriate file paths:
+```html
+
+```
+```scss
+// _sass/_example.scss
+```
+
+### 4. Accessibility Notes
+Explain specifically how accessibility is maintained or improved.
+
+### 5. Responsive Behavior
+Describe how the design adapts across breakpoints.
+
+## UI Review Mode
+
+When auditing an existing page, systematically analyze:
+1. **Visual hierarchy** — Is the content priority clear at a glance?
+2. **Layout balance** — Does whitespace and alignment feel intentional?
+3. **UX friction** — Are there unnecessary clicks, hidden actions, or confusing flows?
+4. **Accessibility issues** — Missing ARIA, poor contrast, non-semantic HTML?
+5. **Responsiveness** — Does it work on mobile without horizontal scroll or overlap?
+6. **Component consistency** — Does it match patterns used elsewhere on the site?
+
+Then provide a prioritized list of specific, actionable improvements.
+
+## Behavioral Rules
+
+**Always:**
+- Think like a senior product designer, not just a developer
+- Justify every UI/UX decision with a usability reason
+- Improve usability before aesthetics
+- Prioritize clarity and simplicity
+- Verify changes are compatible with Bootstrap 4 (not Bootstrap 5)
+- Check that Kramdown rendering rules are respected
+- Confirm production build safety (PurgeCSS, jekyll-terser)
+
+**Never:**
+- Make arbitrary stylistic changes without justification
+- Break existing layout logic or page functionality
+- Introduce visual inconsistency across pages
+- Use Bootstrap 5 APIs or Tailwind utilities (not in this stack)
+- Modify protected files (`Gemfile*`, `package*.json`, `.github/workflows/*`)
+
+**Update your agent memory** as you discover design patterns, recurring component styles, SASS variable names, Bootstrap customizations, and accessibility issues in this codebase. This builds institutional design knowledge across conversations.
+
+Examples of what to record:
+- Existing SASS variables and their values
+- Page-specific layout patterns and how they're achieved
+- Recurring Bootstrap component usage and customizations
+- Accessibility gaps found and fixes applied
+- Color palette values in use across the site
+- Typography classes and spacing conventions established
+- Pages that have known responsive issues
+- Liquid template patterns used in `_layouts/` and `_includes/`
+
+# Persistent Agent Memory
+
+You have a persistent Persistent Agent Memory directory at `/Users/ben/Documents/GitHub/djbsec.github.io/.Codex/agent-memory/ui-ux-frontend-designer/`. Its contents persist across conversations.
+
+As you work, consult your memory files to build on previous experience. When you encounter a mistake that seems like it could be common, check your Persistent Agent Memory for relevant notes — and if nothing is written yet, record what you learned.
+
+Guidelines:
+- `MEMORY.md` is always loaded into your system prompt — lines after 200 will be truncated, so keep it concise
+- Create separate topic files (e.g., `debugging.md`, `patterns.md`) for detailed notes and link to them from MEMORY.md
+- Update or remove memories that turn out to be wrong or outdated
+- Organize memory semantically by topic, not chronologically
+- Use the Write and Edit tools to update your memory files
+
+What to save:
+- Stable patterns and conventions confirmed across multiple interactions
+- Key architectural decisions, important file paths, and project structure
+- User preferences for workflow, tools, and communication style
+- Solutions to recurring problems and debugging insights
+
+What NOT to save:
+- Session-specific context (current task details, in-progress work, temporary state)
+- Information that might be incomplete — verify against project docs before writing
+- Anything that duplicates or contradicts existing AGENTS.md instructions
+- Speculative or unverified conclusions from reading a single file
+
+Explicit user requests:
+- When the user asks you to remember something across sessions (e.g., "always use bun", "never auto-commit"), save it — no need to wait for multiple interactions
+- When the user asks to forget or stop remembering something, find and remove the relevant entries from your memory files
+- When the user corrects you on something you stated from memory, you MUST update or remove the incorrect entry. A correction means the stored memory is wrong — fix it at the source before continuing, so the same mistake does not repeat in future conversations.
+- Since this memory is project-scope and shared with your team via version control, tailor your memories to this project
+
+## Searching past context
+
+When looking for past context:
+1. Search topic files in your memory directory:
+```
+Grep with pattern="
" path="/Users/ben/Documents/GitHub/djbsec.github.io/.Codex/agent-memory/ui-ux-frontend-designer/" glob="*.md"
+```
+2. Session transcript logs (last resort — large files, slow):
+```
+Grep with pattern="" path="/Users/ben/.Codex/projects/-Users-ben-Documents-GitHub-djbsec-github-io/" glob="*.jsonl"
+```
+Use narrow search terms (error messages, file paths, function names) rather than broad keywords.
+
+## MEMORY.md
+
+Your MEMORY.md is currently empty. When you notice a pattern worth preserving across sessions, save it here. Anything in MEMORY.md will be included in your system prompt next time."""
+name = "ui-ux-frontend-designer"
diff --git a/.codex/hooks.json b/.codex/hooks.json
new file mode 100644
index 000000000..6e18d2ac7
--- /dev/null
+++ b/.codex/hooks.json
@@ -0,0 +1,33 @@
+{
+ "hooks": {
+ "PostToolUse": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "node '/Users/ben/Documents/GitHub/djbsec.github.io/.codex/hooks/gsd-context-monitor.js'"
+ }
+ ]
+ },
+ {
+ "matcher": "Write|Edit|MultiEdit|NotebookEdit",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "jq -r --arg ts \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" '\"\\($ts) [\\(.tool_name)] \\(.tool_input.file_path // .tool_input.notebook_path // \"?\")\"' >> \"${CLAUDE_PROJECT_DIR:-.}/claude-changes.log\" 2>/dev/null || true"
+ }
+ ]
+ }
+ ],
+ "SessionStart": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "node '/Users/ben/Documents/GitHub/djbsec.github.io/.codex/hooks/gsd-check-update.js'"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/.codex/hooks/gsd-check-update.js b/.codex/hooks/gsd-check-update.js
new file mode 100644
index 000000000..97628261a
--- /dev/null
+++ b/.codex/hooks/gsd-check-update.js
@@ -0,0 +1,69 @@
+#!/usr/bin/env node
+// Check for GSD updates in background, write result to cache
+// Called by SessionStart hook - runs once per session
+
+const fs = require("fs");
+const path = require("path");
+const os = require("os");
+const { spawn } = require("child_process");
+
+const homeDir = os.homedir();
+const cwd = process.cwd();
+const cacheDir = path.join(homeDir, ".claude", "cache");
+const cacheFile = path.join(cacheDir, "gsd-update-check.json");
+
+// VERSION file locations (check project first, then global)
+const projectVersionFile = path.join(cwd, ".claude", "get-shit-done", "VERSION");
+const globalVersionFile = path.join(homeDir, ".claude", "get-shit-done", "VERSION");
+
+// Ensure cache directory exists
+if (!fs.existsSync(cacheDir)) {
+ fs.mkdirSync(cacheDir, { recursive: true });
+}
+
+// Run check in background (spawn background process, windowsHide prevents console flash)
+const child = spawn(
+ process.execPath,
+ [
+ "-e",
+ `
+ const fs = require('fs');
+ const { execSync } = require('child_process');
+
+ const cacheFile = ${JSON.stringify(cacheFile)};
+ const projectVersionFile = ${JSON.stringify(projectVersionFile)};
+ const globalVersionFile = ${JSON.stringify(globalVersionFile)};
+
+ // Check project directory first (local install), then global
+ let installed = '0.0.0';
+ try {
+ if (fs.existsSync(projectVersionFile)) {
+ installed = fs.readFileSync(projectVersionFile, 'utf8').trim();
+ } else if (fs.existsSync(globalVersionFile)) {
+ installed = fs.readFileSync(globalVersionFile, 'utf8').trim();
+ }
+ } catch (e) {}
+
+ let latest = null;
+ try {
+ latest = execSync('npm view get-shit-done-cc version', { encoding: 'utf8', timeout: 10000, windowsHide: true }).trim();
+ } catch (e) {}
+
+ const result = {
+ update_available: latest && installed !== latest,
+ installed,
+ latest: latest || 'unknown',
+ checked: Math.floor(Date.now() / 1000)
+ };
+
+ fs.writeFileSync(cacheFile, JSON.stringify(result));
+`,
+ ],
+ {
+ stdio: "ignore",
+ windowsHide: true,
+ detached: true, // Required on Windows for proper process detachment
+ }
+);
+
+child.unref();
diff --git a/.codex/hooks/gsd-context-monitor.js b/.codex/hooks/gsd-context-monitor.js
new file mode 100644
index 000000000..73eea7d42
--- /dev/null
+++ b/.codex/hooks/gsd-context-monitor.js
@@ -0,0 +1,124 @@
+#!/usr/bin/env node
+// Context Monitor - PostToolUse hook
+// Reads context metrics from the statusline bridge file and injects
+// warnings when context usage is high. This makes the AGENT aware of
+// context limits (the statusline only shows the user).
+//
+// How it works:
+// 1. The statusline hook writes metrics to /tmp/claude-ctx-{session_id}.json
+// 2. This hook reads those metrics after each tool use
+// 3. When remaining context drops below thresholds, it injects a warning
+// as additionalContext, which the agent sees in its conversation
+//
+// Thresholds:
+// WARNING (remaining <= 35%): Agent should wrap up current task
+// CRITICAL (remaining <= 25%): Agent should stop immediately and save state
+//
+// Debounce: 5 tool uses between warnings to avoid spam
+// Severity escalation bypasses debounce (WARNING -> CRITICAL fires immediately)
+
+const fs = require("fs");
+const os = require("os");
+const path = require("path");
+
+const WARNING_THRESHOLD = 35; // remaining_percentage <= 35%
+const CRITICAL_THRESHOLD = 25; // remaining_percentage <= 25%
+const STALE_SECONDS = 60; // ignore metrics older than 60s
+const DEBOUNCE_CALLS = 5; // min tool uses between warnings
+
+let input = "";
+process.stdin.setEncoding("utf8");
+process.stdin.on("data", (chunk) => (input += chunk));
+process.stdin.on("end", () => {
+ try {
+ const data = JSON.parse(input);
+ const sessionId = data.session_id;
+
+ if (!sessionId) {
+ process.exit(0);
+ }
+
+ const tmpDir = os.tmpdir();
+ const metricsPath = path.join(tmpDir, `claude-ctx-${sessionId}.json`);
+
+ // If no metrics file, this is a subagent or fresh session -- exit silently
+ if (!fs.existsSync(metricsPath)) {
+ process.exit(0);
+ }
+
+ const metrics = JSON.parse(fs.readFileSync(metricsPath, "utf8"));
+ const now = Math.floor(Date.now() / 1000);
+
+ // Ignore stale metrics
+ if (metrics.timestamp && now - metrics.timestamp > STALE_SECONDS) {
+ process.exit(0);
+ }
+
+ const remaining = metrics.remaining_percentage;
+ const usedPct = metrics.used_pct;
+
+ // No warning needed
+ if (remaining > WARNING_THRESHOLD) {
+ process.exit(0);
+ }
+
+ // Debounce: check if we warned recently
+ const warnPath = path.join(tmpDir, `claude-ctx-${sessionId}-warned.json`);
+ let warnData = { callsSinceWarn: 0, lastLevel: null };
+ let firstWarn = true;
+
+ if (fs.existsSync(warnPath)) {
+ try {
+ warnData = JSON.parse(fs.readFileSync(warnPath, "utf8"));
+ firstWarn = false;
+ } catch (e) {
+ // Corrupted file, reset
+ }
+ }
+
+ warnData.callsSinceWarn = (warnData.callsSinceWarn || 0) + 1;
+
+ const isCritical = remaining <= CRITICAL_THRESHOLD;
+ const currentLevel = isCritical ? "critical" : "warning";
+
+ // Emit immediately on first warning, then debounce subsequent ones
+ // Severity escalation (WARNING -> CRITICAL) bypasses debounce
+ const severityEscalated = currentLevel === "critical" && warnData.lastLevel === "warning";
+ if (!firstWarn && warnData.callsSinceWarn < DEBOUNCE_CALLS && !severityEscalated) {
+ // Update counter and exit without warning
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
+ process.exit(0);
+ }
+
+ // Reset debounce counter
+ warnData.callsSinceWarn = 0;
+ warnData.lastLevel = currentLevel;
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
+
+ // Build warning message
+ let message;
+ if (isCritical) {
+ message =
+ `CONTEXT MONITOR CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
+ "STOP new work immediately. Save state NOW and inform the user that context is nearly exhausted. " +
+ "If using GSD, run /gsd:pause-work to save execution state.";
+ } else {
+ message =
+ `CONTEXT MONITOR WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
+ "Begin wrapping up current task. Do not start new complex work. " +
+ "If using GSD, consider /gsd:pause-work to save state.";
+ }
+
+ const output = {
+ hookSpecificOutput: {
+ hookEventName: "PostToolUse",
+ additionalContext: message,
+ },
+ };
+
+ process.stdout.write(JSON.stringify(output));
+ } catch (e) {
+ // Silent fail -- never block tool execution
+ process.exit(0);
+ }
+});
diff --git a/.codex/hooks/gsd-statusline.js b/.codex/hooks/gsd-statusline.js
new file mode 100644
index 000000000..6cce2d5bd
--- /dev/null
+++ b/.codex/hooks/gsd-statusline.js
@@ -0,0 +1,112 @@
+#!/usr/bin/env node
+// Claude Code Statusline - GSD Edition
+// Shows: model | current task | directory | context usage
+
+const fs = require("fs");
+const path = require("path");
+const os = require("os");
+
+// Read JSON from stdin
+let input = "";
+process.stdin.setEncoding("utf8");
+process.stdin.on("data", (chunk) => (input += chunk));
+process.stdin.on("end", () => {
+ try {
+ const data = JSON.parse(input);
+ const model = data.model?.display_name || "Claude";
+ const dir = data.workspace?.current_dir || process.cwd();
+ const session = data.session_id || "";
+ const remaining = data.context_window?.remaining_percentage;
+
+ // Context window display (shows USED percentage scaled to 80% limit)
+ // Claude Code enforces an 80% context limit, so we scale to show 100% at that point
+ let ctx = "";
+ if (remaining != null) {
+ const rem = Math.round(remaining);
+ const rawUsed = Math.max(0, Math.min(100, 100 - rem));
+ // Scale: 80% real usage = 100% displayed
+ const used = Math.min(100, Math.round((rawUsed / 80) * 100));
+
+ // Write context metrics to bridge file for the context-monitor PostToolUse hook.
+ // The monitor reads this file to inject agent-facing warnings when context is low.
+ if (session) {
+ try {
+ const bridgePath = path.join(os.tmpdir(), `claude-ctx-${session}.json`);
+ const bridgeData = JSON.stringify({
+ session_id: session,
+ remaining_percentage: remaining,
+ used_pct: used,
+ timestamp: Math.floor(Date.now() / 1000),
+ });
+ fs.writeFileSync(bridgePath, bridgeData);
+ } catch (e) {
+ // Silent fail -- bridge is best-effort, don't break statusline
+ }
+ }
+
+ // Build progress bar (10 segments)
+ const filled = Math.floor(used / 10);
+ const bar = "█".repeat(filled) + "░".repeat(10 - filled);
+
+ // Color based on scaled usage (thresholds adjusted for new scale)
+ if (used < 63) {
+ // ~50% real
+ ctx = ` \x1b[32m${bar} ${used}%\x1b[0m`;
+ } else if (used < 81) {
+ // ~65% real
+ ctx = ` \x1b[33m${bar} ${used}%\x1b[0m`;
+ } else if (used < 95) {
+ // ~76% real
+ ctx = ` \x1b[38;5;208m${bar} ${used}%\x1b[0m`;
+ } else {
+ ctx = ` \x1b[5;31m💀 ${bar} ${used}%\x1b[0m`;
+ }
+ }
+
+ // Current task from todos
+ let task = "";
+ const homeDir = os.homedir();
+ const todosDir = path.join(homeDir, ".claude", "todos");
+ if (session && fs.existsSync(todosDir)) {
+ try {
+ const files = fs
+ .readdirSync(todosDir)
+ .filter((f) => f.startsWith(session) && f.includes("-agent-") && f.endsWith(".json"))
+ .map((f) => ({ name: f, mtime: fs.statSync(path.join(todosDir, f)).mtime }))
+ .sort((a, b) => b.mtime - a.mtime);
+
+ if (files.length > 0) {
+ try {
+ const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), "utf8"));
+ const inProgress = todos.find((t) => t.status === "in_progress");
+ if (inProgress) task = inProgress.activeForm || "";
+ } catch (e) {}
+ }
+ } catch (e) {
+ // Silently fail on file system errors - don't break statusline
+ }
+ }
+
+ // GSD update available?
+ let gsdUpdate = "";
+ const cacheFile = path.join(homeDir, ".claude", "cache", "gsd-update-check.json");
+ if (fs.existsSync(cacheFile)) {
+ try {
+ const cache = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
+ if (cache.update_available) {
+ gsdUpdate = "\x1b[33m⬆ /gsd:update\x1b[0m │ ";
+ }
+ } catch (e) {}
+ }
+
+ // Output
+ const dirname = path.basename(dir);
+ if (task) {
+ process.stdout.write(`${gsdUpdate}\x1b[2m${model}\x1b[0m │ \x1b[1m${task}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
+ } else {
+ process.stdout.write(`${gsdUpdate}\x1b[2m${model}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
+ }
+ } catch (e) {
+ // Silent fail - don't break statusline on parse errors
+ }
+});
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..5104352f6
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,109 @@
+# AGENTS.md
+
+This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
+
+## Commands
+
+```bash
+# Local development (serves at http://localhost:4000)
+bundle exec jekyll serve
+
+# Production build
+bundle exec jekyll build
+
+# Install Ruby dependencies
+bundle install
+```
+
+The CI pipeline (`.github/workflows/deploy.yml`) also runs `purgecss` and `imagemagick` post-build, but those are not required locally.
+
+## Architecture
+
+This is a **Jekyll static site** using the [al-folio](https://github.com/alshedivat/al-folio) academic theme, hosted on GitHub Pages. Deployment is handled by GitHub Actions — pushes to `main` trigger a build and deploy the `_site/` output to GitHub Pages via `JamesIves/github-pages-deploy-action`.
+
+### Templating & Rendering
+
+- **Markdown parser**: Kramdown with GFM input. **Critical gotcha**: Kramdown does NOT render Markdown (headings, bold, lists) inside raw HTML blocks. Keep page content outside `` wrappers, or add `markdown="1"` to the wrapper element.
+- **Templates**: Liquid (`.liquid` files in `_layouts/` and `_includes/`)
+- **CSS**: Bootstrap 4 + MDB (mdbootstrap), plus SASS in `_sass/`. Styles are compressed and PurgeCSS removes unused selectors in production.
+- **JS**: Minified by jekyll-terser in production (`drop_console: true` is set).
+
+### Navigation
+
+Nav items are auto-generated from pages in `_pages/` with `nav: true` in front matter, sorted by `nav_order`. Current order:
+
+| nav_order | Page |
+| --------- | ----------------------- |
+| 1 | Blog |
+| 2 | Cybersecurity Explained |
+| 3 | EPSS |
+| 4 | AI Tools & Prompts |
+| 5 | Repositories |
+| 6 | Blue Team |
+
+### Collections
+
+- `_posts/` — Daily CyberNews blog posts. Use `_posts/template.md` as a starting point. Front matter: `layout: post`, `tags: CyberNews`, `categories: News`, `thumbnail: assets/img/cybernews.webp`.
+- `_explained/` — Short cybersecurity explainer articles. Front matter: `layout: page`, `category: explained`, `img: assets/img/projects/
.png`.
+- `_news/` — Short news items (displayed on the about/home page).
+
+### Key Files & Data
+
+- `_config.yml` — All site settings: theme, plugins, collections, third-party library versions.
+- `_data/repositories.yml` — GitHub repos shown on the Repositories page. Add/remove entries under `github_repos`.
+- `_includes/cve_lookup.html` — The EPSS CVE lookup tool (client-side JS + external APIs).
+- `_includes/repository/repo.liquid` / `repo_user.liquid` — Render GitHub repo/user cards using GitHub's OpenGraph CDN (`opengraph.githubassets.com/1/{owner}/{repo}`).
+- `_pages/` — All navigable pages. Each is a standalone Markdown/HTML file with Liquid front matter.
+- `assets/json/resume.json` — Resume data loaded by jekyll-get-json at build time.
+
+### EPSS Tool (`_includes/cve_lookup.html`)
+
+- Backend: Cloudflare Worker at `epss-worker.bsherrill676.workers.dev/get_epss` (POST with `{cve, date}`)
+- EPSS history: `https://api.first.org/data/v1/epss?cve=&scope=time-series` — data is at `response.data[0]["time-series"]`. The `?days=30` parameter returns empty data; use `?scope=time-series` instead.
+- CISA KEV: fetched from `https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json`
+- Chart.js is loaded dynamically from CDN only when needed.
+
+### Page Patterns
+
+New nav pages follow this front matter structure:
+
+```yaml
+---
+layout: page
+title: Page Title
+permalink: /page-slug/
+description: Short description shown in meta/subtitle
+nav: true
+nav_order: N
+---
+```
+
+Tool/resource pages (like Blue Team, AI Tools) use Bootstrap tables with `table-hover` and `table-dark` header for consistent styling. Cards use Bootstrap's `card` class with colored `card-header` (`bg-danger`, `bg-primary`, etc.).
+
+## GSD Workflow (Task Management)
+
+Use a simple GSD workflow stored in `.gsd/`:
+
+- Backlog: `.gsd/backlog.md`
+- Doing: `.gsd/doing.md`
+- Done: `.gsd/done.md`
+
+Rules:
+
+1. When I ask you to plan work, create clear, small tasks in `backlog.md`.
+2. When starting work, move exactly one task into `doing.md` and include:
+ - branch name (must be `ai/` or `feature/`)
+ - acceptance criteria
+ - files you expect to change
+3. When finished, move it to `done.md` with a short changelog and testing results.
+
+Completion definition (required):
+
+- `JEKYLL_ENV=production bundle exec jekyll build` passes.
+- Summarize changed files and how to verify locally.
+
+Safety:
+
+- Work only on the current git branch. Never switch branches.
+- Never push to `main`/`master` directly.
+- Do not modify `Gemfile*`, `package*.json`, or `.github/workflows/*` unless explicitly asked.
diff --git a/_includes/home-cards.html b/_includes/home-cards.html
index 7e7c8fe09..79c7757b9 100644
--- a/_includes/home-cards.html
+++ b/_includes/home-cards.html
@@ -1,5 +1,6 @@
{% assign latest_post = site.posts | first %} {% assign explained_posts = site.explained | sort: 'date' | reverse %} {% assign explained_post =
-explained_posts | first %} {% assign next_conf = site.data.cybersecurity_calendar | sort: 'start_date' | first %}
+explained_posts | first %} {% assign today = site.time | date: '%Y-%m-%d' %} {% assign upcoming_confs = site.data.cybersecurity_calendar | where_exp:
+'c', 'c.end_date >= today' | sort: 'start_date' %} {% assign next_conf = upcoming_confs | first %}
-
-
-
Ivanti Connect Secure — RCE
-
EPSS 0.94 · CVSS 9.8 · KEV
-
-
-
Fortinet FortiOS — Auth Bypass
-
EPSS 0.87 · CVSS 9.1 · KEV
-
-
-
Palo Alto PAN-OS — DoS
-
EPSS 0.61 · CVSS 7.5 · KEV
-
+ {% if latest_post.cves and latest_post.cves.size > 0 %}
+ {% for cve in latest_post.cves limit: 3 %}
+
+
{{ cve.name }}
+
+ EPSS {{ cve.epss }} · CVSS {{ cve.cvss }}{% if cve.kev %} · KEV{% endif %}
+
+
+ {% endfor %}
+ {% else %}
+
Example CVEs — see latest briefing for live intel.
+
+
Ivanti Connect Secure — RCE
+
EPSS 0.94 · CVSS 9.8 · KEV
+
+
+
Fortinet FortiOS — Auth Bypass
+
EPSS 0.87 · CVSS 9.1 · KEV
+
+
+
Palo Alto PAN-OS — DoS
+
EPSS 0.61 · CVSS 7.5 · KEV
+
+ {% endif %}
diff --git a/_layouts/home.liquid b/_layouts/home.liquid
index 89f5fe9f1..0214a8de1 100644
--- a/_layouts/home.liquid
+++ b/_layouts/home.liquid
@@ -14,7 +14,7 @@ layout: default
diff --git a/_pages/cyber-books.md b/_pages/cyber-books.md
index 0beda1469..86dedd673 100644
--- a/_pages/cyber-books.md
+++ b/_pages/cyber-books.md
@@ -3,7 +3,7 @@ layout: page
title: Cybersecurity Books
permalink: /books/
subtitle:
-description: List of Cybersercurity Books I recommend
+description: List of Cybersecurity Books I recommend
nav: false
nav_order: 2
#profile:
diff --git a/_pages/cyber-learning-platforms.md b/_pages/cyber-learning-platforms.md
index f9c0f6b37..f46deae80 100644
--- a/_pages/cyber-learning-platforms.md
+++ b/_pages/cyber-learning-platforms.md
@@ -3,7 +3,7 @@ layout: page
title: Cybersecurity Learning Platforms
permalink: /platforms/
subtitle:
-description: List of Cybersercurity Learning Platforms
+description: List of Cybersecurity Learning Platforms
nav: false
nav_order: 2
---
diff --git a/_posts/template.md b/_posts/template.md
index 3e9568430..a2da80197 100644
--- a/_posts/template.md
+++ b/_posts/template.md
@@ -8,6 +8,17 @@ categories: News
thumbnail: assets/img/cybernews.webp
featured: false
published: false
+# Optional: top CVEs covered in this briefing. When present on the latest post,
+# the home page CVE block renders these instead of the example placeholder.
+# cves:
+# - name: Ivanti Connect Secure — RCE
+# epss: 0.94
+# cvss: 9.8
+# kev: true
+# - name: Fortinet FortiOS — Auth Bypass
+# epss: 0.87
+# cvss: 9.1
+# kev: true
---
# Filename convention for same-day posts: