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
74 changes: 74 additions & 0 deletions data/security-guides.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[
{
"id": "guide-sec-001",
"title": "Agent Security Baseline Checklist",
"content": "Establish a baseline before deploying any agent: define trust boundaries, enforce least privilege, run dependency audits, and require logging for all sensitive actions.",
"category": "general",
"severity": "high",
"tags": ["baseline", "hardening", "checklist"],
"updatedAt": "2026-02-09T10:00:00.000Z"
},
{
"id": "guide-sec-002",
"title": "Incident Response for Agent Systems",
"content": "Maintain an agent-focused incident playbook: isolate compromised sessions, revoke credentials, preserve forensic logs, and publish postmortems with corrective actions.",
"category": "general",
"severity": "medium",
"tags": ["incident-response", "operations", "forensics"],
"updatedAt": "2026-02-09T10:30:00.000Z"
},
{
"id": "guide-sec-003",
"title": "Prompt Injection Detection and Blocking",
"content": "Use layered detection with signature rules, semantic checks, and policy enforcement. Reject inputs that attempt to override system behavior or exfiltrate secrets.",
"category": "injection",
"severity": "critical",
"tags": ["prompt-injection", "input-validation", "policy"],
"updatedAt": "2026-02-09T11:00:00.000Z"
},
{
"id": "guide-sec-004",
"title": "Output Guardrails Against Data Exfiltration",
"content": "Apply output allowlists and redaction filters to prevent accidental leaks. Block responses that contain credentials, private keys, or high-risk internal identifiers.",
"category": "injection",
"severity": "high",
"tags": ["output-filtering", "redaction", "exfiltration"],
"updatedAt": "2026-02-09T11:20:00.000Z"
},
{
"id": "guide-sec-005",
"title": "TLS and Certificate Validation",
"content": "Require HTTPS everywhere, enforce modern TLS versions, verify certificates, and pin certs for critical endpoints to reduce man-in-the-middle risk.",
"category": "network",
"severity": "high",
"tags": ["tls", "encryption", "transport"],
"updatedAt": "2026-02-09T11:40:00.000Z"
},
{
"id": "guide-sec-006",
"title": "Webhook and API Abuse Protection",
"content": "Verify webhook signatures, enforce strict auth, and apply multi-tier rate limits. Monitor anomalies to contain brute-force and replay attempts quickly.",
"category": "network",
"severity": "medium",
"tags": ["webhooks", "rate-limiting", "api-security"],
"updatedAt": "2026-02-09T12:00:00.000Z"
},
{
"id": "guide-sec-007",
"title": "Secret Storage and Rotation",
"content": "Store secrets in managed vaults, never in source control. Rotate high-risk credentials frequently, and use short-lived tokens with scoped permissions.",
"category": "secrets",
"severity": "critical",
"tags": ["secrets", "vault", "rotation"],
"updatedAt": "2026-02-09T12:20:00.000Z"
},
{
"id": "guide-sec-008",
"title": "Audit Trails for Secret Access",
"content": "Log all secret reads and writes with actor, service, and timestamp metadata. Alert on repeated failed access and unusual request patterns.",
"category": "secrets",
"severity": "low",
"tags": ["audit", "monitoring", "compliance"],
"updatedAt": "2026-02-09T12:40:00.000Z"
}
]
110 changes: 110 additions & 0 deletions src/app/api/security-guide/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { NextRequest, NextResponse } from "next/server";
import {
filterSecurityGuides,
normalizeGuideCategory,
normalizeGuideSeverity,
readSecurityGuides,
type SecurityGuide,
type SecurityGuideCategory,
type SecurityGuideSeverity,
writeSecurityGuides,
} from "@/lib/security-guides";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

function createGuideId(): string {
const suffix = Math.random().toString(36).slice(2, 10);
return `guide-${Date.now()}-${suffix}`;
}

export async function GET(request: NextRequest) {
try {
const categoryParam = request.nextUrl.searchParams.get("category");
const severityParam = request.nextUrl.searchParams.get("severity");
const search = request.nextUrl.searchParams.get("search");

if (categoryParam && !normalizeGuideCategory(categoryParam)) {
return NextResponse.json(
{ error: "Invalid category. Use injection, network, secrets, or general." },
{ status: 400 }
);
}

if (severityParam && !normalizeGuideSeverity(severityParam)) {
return NextResponse.json(
{ error: "Invalid severity. Use critical, high, medium, or low." },
{ status: 400 }
);
}

const guides = await readSecurityGuides();
const filteredGuides = filterSecurityGuides(guides, {
category: categoryParam,
severity: severityParam,
search,
});

return NextResponse.json(
{
guides: filteredGuides,
total: filteredGuides.length,
},
{
headers: {
"Cache-Control": "no-store",
},
}
);
} catch (error) {
console.error("Failed to load security guides", error);
return NextResponse.json({ error: "Failed to load security guides" }, { status: 500 });
}
}

export async function POST(request: NextRequest) {
try {
const body = (await request.json()) as Record<string, unknown>;

const title = typeof body.title === "string" ? body.title.trim() : "";
const content = typeof body.content === "string" ? body.content.trim() : "";
const categoryRaw = typeof body.category === "string" ? body.category : "";
const severityRaw = typeof body.severity === "string" ? body.severity : "";
const tags = Array.isArray(body.tags)
? body.tags.filter((tag): tag is string => typeof tag === "string" && tag.trim().length > 0)
: [];

const category = normalizeGuideCategory(categoryRaw) as SecurityGuideCategory | null;
const severity = normalizeGuideSeverity(severityRaw) as SecurityGuideSeverity | null;

if (!title || !content || !category || !severity) {
return NextResponse.json(
{
error:
"title, content, category (injection|network|secrets|general), and severity (critical|high|medium|low) are required",
},
{ status: 400 }
);
}

const guides = await readSecurityGuides();

const newGuide: SecurityGuide = {
id: createGuideId(),
title,
content,
category,
severity,
tags,
updatedAt: new Date().toISOString(),
};

const updatedGuides = [...guides, newGuide];
await writeSecurityGuides(updatedGuides);

return NextResponse.json({ guide: newGuide }, { status: 201 });
} catch (error) {
console.error("Failed to create security guide", error);
return NextResponse.json({ error: "Failed to create security guide" }, { status: 500 });
}
}
Loading
Loading