Works with the AI Agents you already use
Secure Code Review for AI-Written Code
Eight agent skills and two scanners that find and fix the authz, injection, SSRF, XSS, secret-leak and supply-chain bugs AI agents write, mapped to OWASP 2025.
$29
Secure Code Review for AI-Written Code
Example session with this skill installed
We're launching our invoicing app next week. Most of it came out of Claude Code. Do a security review of the Next.js app and fix what's critical.
- Read your context and instructions
- Compiled the secure code review
The agent loads secure-code-review, runs the pre-flight, and starts with the scanner:
$ node scan-code.mjs .
app\invoices\PayButton.tsx:9 HIGH public-env-secret CWE-200 Secret-looking variable behind a public env prefix
headers: { Authorization: `Bearer ${process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY}` },
fix: Public prefixes are inlined into the client bundle at build time. Rename without the prefix and read it only in server code.
app\invoices\actions.ts:6 MEDIUM server-action-no-auth CWE-862 Server Action deleteInvoice has no visible authentication or authorization check
export async function deleteInvoice(id: string) {
fix: Server Actions are public POST endpoints. Verify the session and the caller's right to this specific record inside the action (or in the data layer it calls), and validate arguments with a schema.
Scanned 9 files: 1 high, 1 medium, 0 low.
It builds for production and checks what actually ships to browsers:
$ node check-build-secrets.mjs --env .env.production
.next\static\chunks\442-02vu_mtss.js:1 HIGH stripe-secret-key CWE-798 Stripe live secret or restricted key sk_live_De...
Checked 11 files in .next\static: 1 high, 0 other.
Mapping the attack surface turns up what the line scanner cannot see: GET /api/invoices/[id] loads findUnique({ where: { id } }) with no session and no owner check. On a local instance an anonymous request returned another organization's invoice with status 200. The report lists three findings:
Critical live Stripe secret key in the client bundle (A02/CWE-798; rotate the key now),
High IDOR on invoices (A01/CWE-639, ASVS 8.2.2),
High unauthenticated Server Action deleting any invoice (A01/CWE-862, ASVS 8.2.1).
The fix follows access-control-review: one server-only data access layer that every caller goes through.
import 'server-only';
import { cache } from 'react';
import { cookies } from 'next/headers';
import { jwtVerify } from 'jose';
import { db } from '@/lib/db';
const secret = process.env.SESSION_SECRET;
if (!secret) throw new Error('SESSION_SECRET is not set');
const key = new TextEncoder().encode(secret);
export const verifySession = cache(async () => {
const token = (await cookies()).get('__Host-session')?.value;
if (!token) throw new AuthError(401);
try {
const { payload } = await jwtVerify(token, key, { algorithms: ['HS256'], issuer: 'app', audience: 'app' });
return { userId: String(payload.sub), orgId: String(payload.org), role: payload.role === 'admin' ? 'admin' : 'member' };
} catch {
throw new AuthError(401);
}
});
export class AuthError extends Error {
constructor(public status: 401 | 403 | 404) { super(String(status)); }
}
export async function getInvoice(id: string) {
const session = await verifySession();
const row = await db.invoice.findFirst({ where: { id, orgId: session.orgId } });
if (!row) throw new AuthError(404);
return { id: row.id, number: row.number, totalCents: row.totalCents, status: row.status };
}
export async function deleteInvoice(id: string) {
const session = await verifySession();
if (session.role !== 'admin') throw new AuthError(403);
const { count } = await db.invoice.deleteMany({ where: { id, orgId: session.orgId } });
if (count === 0) throw new AuthError(404);
}
The Server Action becomes await verifySession(); const id = z.uuid().parse(rawId); await deleteInvoice(id);, the Route Handler maps AuthError to its status, and the Stripe call moves to an authenticated Route Handler that reads STRIPE_SECRET_KEY on the server. After the rebuild:
$ node scan-code.mjs .
Scanned 11 files: 0 high, 0 medium, 0 low.
$ node check-build-secrets.mjs --env .env.production
Checked 11 files in .next\static: 0 high, 0 other.
$ curl (no cookie) /api/invoices/<id> -> 401
$ curl (org B session) /api/invoices/<id> -> 404
$ curl (org A session) /api/invoices/<id> -> 200 {"id":"...","number":"INV-1","totalCents":1000,"status":"open"}
$ curl (no cookie) POST /api/pay -> 401
All output above is real, from a Next.js 16.4.0 production build with the pack's scripts. The agent then adds the three-case authorization test from verify-fixes.md for each protected operation and puts both scripts in CI.
Connects securely to your tools. The creator never sees your data.
About this skill
AI agents write code that works and ships with the same holes every time: Server Actions anyone can POST to because the page checked auth, invoice lookups by id with no owner condition, update(req.body) that lets a user set their own role, a Stripe secret key behind NEXT_PUBLIC_ because the browser said "undefined", jwt.decode where verify was needed, fetch(userUrl) for link previews, model output in dangerouslySetInnerHTML, || 'dev-secret' fallbacks, and package names that do not exist until an attacker registers them.
This pack gives your agent a review method and the exact fixes, checked against OWASP Top 10 2025, ASVS 5.0, the OWASP LLM Top 10 2025, CWE 4.20 and current framework docs and advisories:
- secure-code-review: entry point with pre-flight, attack-surface mapping, severity rubric, and a finding format with evidence, fix and regression test for every issue.
- access-control-review: IDOR, missing authorization on Server Actions and API routes, a data access layer pattern, tenant isolation, mass assignment, CSRF, CORS, rate limits behind proxies.
- auth-session-review: JWT verification (jose, jsonwebtoken, PyJWT) that rejects
none, key confusion, wrong audience and missingexp; cookies, sessions, password hashing, reset tokens, OAuth callbacks. - injection-review: SQL, NoSQL, command, template injection, SSRF with a tested guard, path traversal, open redirects, XSS in React 19 and Next.js, deserialization, uploads.
- framework-hardening: Next.js 16 (proxy.ts, CSP nonces, image optimizer, every 2025-2026 high and critical advisory with fixed versions), Express 5, Fastify 5, Django 6, FastAPI, Supabase RLS.
- secrets-exposure: env prefixes per framework, client bundles, logs, and a leak response runbook.
- supply-chain-review: npm 12
allowScripts, pnpmallowBuilds, release-age gates, hallucinated and typosquatted packages, provenance, trusted publishing. - llm-app-security: prompt injection, tool permissions with user-scoped authorization and confirmation, output handling, RAG filters, limits.
Two zero-dependency Node scripts: scan-code.mjs (45 rules for JS/TS and Python, each finding with file:line, CWE and fix hint) and check-build-secrets.mjs (provider keys, connection strings, .env files, source maps and your own server env values in production build output). Both only read files.
Every helper in the pack was typechecked and run against bypass inputs; SQL against PostgreSQL 18; Python against Django 6.1 and FastAPI 0.143; Next.js patterns in a real 16.4 build. Defensive scope: it reviews code you own and writes no exploits.
How to use
Skills on Agensi run inside your AI agent. Copy the prompt, paste it into your agent, and it connects to Agensi and installs this skill for you. If a payment is needed, your agent shows it to you first.
Reviews
No reviews yet
Be one of the first to try it. Every listed skill passes our trust checks below.
Security scanned
Passed our 8-point scan before listing
Fresh listing
Recently published to Agensi
Money-back guarantee
Doesn't do what its page promises? You get your money back.
Trust & safety
Security scanned
Verified clean 6 days ago
- Passed all security checks, Safe to install
Requires