chore: remove finding-ID prefixes from code comments

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-03-26 12:51:39 +01:00
parent 4f2f090e2c
commit b480c2cf5d
16 changed files with 24 additions and 29 deletions
+2 -2
View File
@@ -202,7 +202,7 @@ function isL4ProxyHost(value: unknown): value is NonNullable<SyncPayload["data"]
}
/**
* H8: Validate semantic content of proxy host fields to prevent
* Validate semantic content of proxy host fields to prevent
* config injection via compromised master or stolen sync token.
*/
function validateProxyHostContent(host: Record<string, unknown>): string | null {
@@ -341,7 +341,7 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ error: "Invalid sync payload structure" }, { status: 400 });
}
// H8: Semantic validation of proxy host content
// Semantic validation of proxy host content
for (const host of (payload as SyncPayload).data.proxyHosts) {
const err = validateProxyHostContent(host as unknown as Record<string, unknown>);
if (err) {
+2 -2
View File
@@ -15,7 +15,7 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// M3: Rate limit password change attempts to prevent brute-forcing current password
// Rate limit password change attempts to prevent brute-forcing current password
const rateLimitKey = `password-change:${session.user.id}`;
const rateCheck = isRateLimited(rateLimitKey);
if (rateCheck.blocked) {
@@ -28,7 +28,7 @@ export async function POST(request: NextRequest) {
const body = await request.json();
const { currentPassword, newPassword } = body;
// L4: Enforce password complexity matching production admin password requirements
// Enforce password complexity matching production admin password requirements
if (!newPassword || newPassword.length < 12) {
return NextResponse.json(
{ error: "New password must be at least 12 characters long" },
+1 -1
View File
@@ -21,7 +21,7 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ error: "name is required" }, { status: 400 });
}
// C3: Validate expires_at before passing to createApiToken
// Validate expires_at before passing to createApiToken
if (body.expires_at !== undefined && body.expires_at !== null && typeof body.expires_at !== "string") {
return NextResponse.json({ error: "expires_at must be a string (ISO 8601 date)" }, { status: 400 });
}
+1 -2
View File
@@ -111,9 +111,8 @@ services:
retries: 3
start_period: 10s
# H2: Docker socket proxy — restricts API surface exposed to l4-port-manager.
# Docker socket proxy — restricts API surface exposed to l4-port-manager.
# Only allows GET, POST to /containers/ and /compose/ endpoints.
# Prevents container escape via unrestricted Docker API access.
docker-socket-proxy:
container_name: caddy-proxy-manager-docker-proxy
image: tecnativa/docker-socket-proxy:latest
+2 -3
View File
@@ -20,9 +20,8 @@ const nextConfig = {
}
},
output: 'standalone',
// M6: Security headers (CSP, X-Frame-Options, etc.) are set per-request in
// proxy.ts middleware with a unique nonce, so they are NOT defined here.
// Static headers() would override the nonce-based CSP with a nonce-less one.
// Security headers (CSP, etc.) are set per-request in proxy.ts middleware
// with a unique nonce, so they are NOT defined here as static headers.
};
export default nextConfig;
+1 -1
View File
@@ -13,7 +13,7 @@ import crypto from "node:crypto";
const isDev = process.env.NODE_ENV === "development";
/**
* M6: Build a nonce-based Content-Security-Policy per request.
* Build a nonce-based Content-Security-Policy per request.
* Next.js reads the nonce from the CSP request header and applies it
* to all inline scripts it generates.
*/
+1 -1
View File
@@ -46,7 +46,7 @@ export async function authenticateApiRequest(
throw new ApiAuthError("Unauthorized", 401);
}
// M14: Deny access when role is missing rather than defaulting to "user"
// Deny access when role is missing rather than defaulting to "user"
const role = session.user.role;
if (!role) {
throw new ApiAuthError("Session missing role claim", 401);
+3 -5
View File
@@ -392,7 +392,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
session.user.id = token.id as string;
session.user.provider = token.provider as string;
// H1: Always fetch current role and avatar from database to reflect
// Always fetch current role from database to reflect
// role changes (e.g. demotion) without waiting for JWT expiry
const userId = Number(token.id);
const currentUser = await getUserById(userId);
@@ -409,7 +409,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
},
},
secret: config.sessionSecret,
// H7: Only trust Host header when explicitly opted in or when NEXTAUTH_URL
// Only trust Host header when explicitly opted in or when NEXTAUTH_URL
// is set (operator has declared the canonical URL, so Host validation is moot).
trustHost: !!process.env.NEXTAUTH_TRUST_HOST || !!process.env.NEXTAUTH_URL,
basePath: "/api/auth",
@@ -451,10 +451,8 @@ export async function requireAdmin() {
*/
export function checkSameOrigin(request: NextRequest): NextResponse | null {
const origin = request.headers.get("origin");
// L1: For mutating requests, require Origin header to be present.
// For mutating requests, require Origin header to be present.
// Browsers always send Origin on cross-origin POST/PUT/DELETE.
// A missing Origin on a mutating request from a cookie-authenticated session
// could indicate a non-browser attacker with a stolen cookie.
const method = request.method.toUpperCase();
const isMutating = method !== "GET" && method !== "HEAD" && method !== "OPTIONS";
if (!origin) {
+2 -2
View File
@@ -108,7 +108,7 @@ export function buildWafHandler(waf: WafSettings, allowWebsocket = false): Recor
);
}
// L7: Runtime-validate excluded_rule_ids are positive integers
// Runtime-validate excluded_rule_ids are positive integers
if (waf.excluded_rule_ids?.length) {
const validIds = waf.excluded_rule_ids.filter(
(id): id is number => typeof id === "number" && Number.isFinite(id) && id > 0 && Number.isInteger(id)
@@ -132,7 +132,7 @@ export function buildWafHandler(waf: WafSettings, allowWebsocket = false): Recor
'SecResponseBodyAccess Off',
);
// H5: Validate WAF custom directives — block dangerous engine-level overrides
// Block dangerous engine-level overrides in custom directives
if (waf.custom_directives?.trim()) {
const directives = waf.custom_directives.trim();
const forbiddenPatterns = [
+2 -2
View File
@@ -800,7 +800,7 @@ async function buildProxyRoutes(
outpostRoute = {
match: [
{
// M10: Sanitize outpostDomain to prevent path traversal and placeholder injection
// Sanitize outpostDomain to prevent path traversal and placeholder injection
path: [`/${authentik.outpostDomain.replace(/\.\./g, '').replace(/\{[^}]*\}/g, '').replace(/\/+/g, '/')}/*`]
}
],
@@ -879,7 +879,7 @@ async function buildProxyRoutes(
}
// Structured path prefix rewrite
// M9: Sanitize path_prefix to prevent Caddy placeholder injection
// Sanitize path_prefix to prevent Caddy placeholder injection
if (meta.rewrite?.path_prefix) {
const safePrefix = meta.rewrite.path_prefix.replace(/\{[^}]*\}/g, '');
if (safePrefix) {
+1 -2
View File
@@ -30,8 +30,7 @@ function resolveSessionSecret(): string {
return DEV_SECRET;
}
// C1: Fail-closed on unrecognized NODE_ENV to prevent silent DEV_SECRET usage
// in staging, test, or misconfigured environments.
// Fail-closed on unrecognized NODE_ENV to prevent silent DEV_SECRET usage
if (!isDevelopment && !isProduction && !secret) {
throw new Error(
`SESSION_SECRET is required when NODE_ENV="${process.env.NODE_ENV ?? ""}" ` +
+1 -1
View File
@@ -161,7 +161,7 @@ function insertBatch(rows: typeof trafficEvents.$inferInsert[]): void {
function purgeOldEntries(): void {
const cutoff = Math.floor(Date.now() / 1000) - RETENTION_DAYS * 86400;
// M5: Use parameterized query instead of string interpolation
// Use parameterized query instead of string interpolation
db.run(sql`DELETE FROM traffic_events WHERE ts < ${cutoff}`);
}
+1 -1
View File
@@ -34,7 +34,7 @@ export async function createApiToken(
createdBy: number,
expiresAt?: string
): Promise<{ token: ApiToken; rawToken: string }> {
// C3: Validate expires_at is a valid ISO 8601 date in the future
// Validate expires_at is a valid ISO 8601 date in the future
let validatedExpiresAt: string | null = null;
if (expiresAt) {
const parsed = new Date(expiresAt);
+1 -1
View File
@@ -12,7 +12,7 @@ export type AuditEvent = {
created_at: string;
};
// L6: Escape LIKE metacharacters so user input is treated as literal text
// Escape LIKE metacharacters so user input is treated as literal text
function escapeLikePattern(input: string): string {
return input.replace(/[%_\\]/g, (ch) => `\\${ch}`);
}
+2 -2
View File
@@ -32,7 +32,7 @@ export function encryptSecret(value: string): string {
}
/**
* L5: Legacy fallback is time-limited. After the migration grace period,
* Legacy fallback is time-limited. After the migration grace period,
* the legacy key is no longer tried, forcing re-encryption of old secrets.
* Set LEGACY_KEY_CUTOFF_DATE env var to extend/disable (ISO 8601 date or "never").
*/
@@ -49,7 +49,7 @@ export function decryptSecret(value: string): string {
try {
return _decryptWithKey(value, deriveKey());
} catch (hkdfError: unknown) {
// L5: Only fall back to legacy key within the grace period
// Only fall back to legacy key within the grace period
if (LEGACY_KEY_CUTOFF && new Date() > LEGACY_KEY_CUTOFF) {
throw new Error(
"[secret] HKDF decryption failed and legacy key grace period has expired. " +
+1 -1
View File
@@ -213,7 +213,7 @@ function insertBatch(rows: typeof wafEvents.$inferInsert[]): void {
function purgeOldEntries(): void {
const cutoff = Math.floor(Date.now() / 1000) - RETENTION_DAYS * 86400;
// M5: Use parameterized query instead of string interpolation
// Use parameterized query instead of string interpolation
db.run(sql`DELETE FROM waf_events WHERE ts < ${cutoff}`);
}