CtrlK
BlogDocsLog inGet started
Tessl Logo

security-hardening

Security architecture including authentication, authorization, RLS policies, CSP, input validation, and API security. Use when implementing auth flows, writing RLS policies, configuring CSP/headers, validating inputs, or auditing security. Trigger terms: RLS, CSP, Server Actions, Zod, auth flow

100

Quality

100%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

SKILL.md
Quality
Evals
Security

Security Hardening

Architecture

LayerToolProtection
EdgeWAF / CDNDDoS, bot detection
HeadersFramework configHSTS, CSP, X-Frame-Options
MiddlewareProxy layerSession refresh, protected routes
Server ActionsAuth providerAuthentication, CSRF
DatabaseRLS PoliciesRow-level authorization
API RoutesCRON_SECRETCron job authorization
InputZodSchema validation
Rate LimitingProxy layerIP-based throttling

Authentication

Auth provider with Server Actions pattern. Resolve library via database capability slot in skill matrix.

ConcernApproach
Sign in/up/outServer Actions (POST-only → automatic CSRF protection)
Session refreshMiddleware updateSession(), HTTP-only cookies
Protected routesMiddleware check
OAuthConfigured in auth provider dashboard
User rolesprofiles.roles TEXT[]
Cron authCRON_SECRET env var, Bearer token in authorization header

CSP

Principle of least privilege. External domains are project-specific (see deployment customization).

  • default-src 'self' — deny by default
  • object-src 'none' — block plugins
  • frame-ancestors 'self' — prevent clickjacking
  • upgrade-insecure-requests — enforce HTTPS
  • Whitelist only required external domains per directive

Note: 'unsafe-inline'/'unsafe-eval' may be required in dev mode — use nonces/hashes in production.

Examples — Next.js next.config.js headers and middleware pattern:

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          {
            key: 'Content-Security-Policy',
            // minimal example; restrict further per app needs
            value: "default-src 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://api.example.com;",
          },
        ],
      },
    ];
  },
};
// middleware.js (Next.js Edge middleware example)
import { NextResponse } from 'next/server';

export function middleware(request) {
  const res = NextResponse.next();
  res.headers.set('Content-Security-Policy', "default-src 'self'; img-src 'self' data:;");
  return res;
}

RLS

SQL examples and role system: See the database skill (authoritative source for RLS).

  • ALTER TABLE x ENABLE ROW LEVEL SECURITY; on all tables
  • Use auth.uid() for auth checks; EXISTS subqueries for role checks
  • Never rely solely on client-side authorization; never disable RLS in production

RLS verification & test pattern

  1. Confirm RLS is enabled for a table (Postgres):
-- run in psql
SELECT relname, relrowsecurity
FROM pg_class
WHERE relname = 'your_table_name';

relrowsecurity = true indicates RLS enabled.

  1. Test pattern: verify a user without privileges cannot read rows.
-- As owner (create test row)
INSERT INTO your_table_name (id, owner_id, data) VALUES (1, 'owner-uid', 'secret');

-- As another_role (should return zero rows if RLS correct)
SET ROLE other_role;
SELECT * FROM your_table_name WHERE id = 1;
-- expected: 0 rows

Automate this check in CI: run the enabling query and a simple positive/negative test as part of the security gate.

Server Action Zod example

'use server';
import { z } from 'zod';
import { revalidatePath } from 'next/cache';

const schema = z.object({ name: z.string().min(1), price: z.number().positive() });

export async function createItem(formData: FormData) {
  const parsed = schema.safeParse(Object.fromEntries(formData.entries()));
  if (!parsed.success) return { error: 'Validation failed', details: parsed.error.format() };
  // insert into DB ...
  revalidatePath('/items');
  return { success: true };
}

API Security

// Cron authorization pattern
const authHeader = request.headers.get('authorization');
if (!authHeader || authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

Generate secret: openssl rand -hex 32. Rotate quarterly.

Input: Zod schemas in all Server Actions and route handlers; React Hook Form client-side.

Critical Rules

  1. Never commit secrets — use env vars.
  2. Server Actions for all auth operations.
  3. RLS on all tables — default-deny, explicit-allow.
  4. Validate all inputs with Zod before DB operations.
  5. Sanitize user content (escape HTML).
  6. Parameterized queries (DB client handles automatically).
  7. Rotate secrets quarterly.

Implementation checklist

  1. Enable RLS on tables and add an automated enablement check in CI (example: SELECT relrowsecurity FROM pg_class WHERE relname = 'your_table').
  2. Configure authentication and session middleware; verify via an integration smoke test against a protected endpoint (e.g., /api/me).
  3. Add CSP and security headers in next.config.js or middleware; validate headers with curl -I against a preview URL.
  4. Add Zod validation to all Server Actions and route handlers (see Zod example above).
  5. Run a security audit (RLS positive/negative tests, header validation, and input fuzzing) and block merges on failing gates.

Cross-reference: see api-patterns/SKILL.md for Server Action patterns and session-checkpoints/SKILL.md for checkpointing security-sensitive work.

Repository
monkilabs/opencastle
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.