
Security Review
Run a scoped security review that flags language-specific dangerous APIs and framework misconfigurations in JavaScript, TypeScript, React, Next.js, and Express code.
Overview
Security Review is an agent skill most often used in Ship (also Build) that guides scoped code review with language-specific vulnerability patterns for JavaScript, TypeScript, Node, React, Next.js, and Express.
Install
npx skills add https://github.com/github/awesome-copilot --skill security-reviewWhat is this skill?
- Step 1 scope resolution: load language-specific vulnerability sections after identifying stack languages
- JavaScript/TypeScript critical API flags including eval, Function constructor, child_process.exec, and unsafe fs paths
- Express checklist: missing helmet, oversized JSON bodies, permissive CORS, and trust-proxy misconfiguration
- React and Next.js patterns: dangerouslySetInnerHTML XSS, javascript: URL injection, unauthenticated Server Actions, API
- Designed as an augment to systematic review passes, not a substitute for dependency scanning or runtime pentests
- Documented Step 1: Scope Resolution before language-specific pattern load
- Language pack emphasis: JavaScript/TypeScript across Node.js, React, Next.js, and Express
Adoption & trust: 3k installs on skills.sh; 34.6k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are about to ship or merge JS/TS changes but lack a consistent checklist for the dangerous APIs and framework defaults that actually show up in indie codebases.
Who is it for?
Solo builders shipping Node, React, or Next.js apps who want agent-assisted SAST-style pattern review on diffs they already have open.
Skip if: Non-JS stacks with no Node surface, orgs needing formal compliance attestations, or teams that require automated SCA-only gates without human-readable findings.
When should I use this skill?
During security-focused code review after scope and languages are known, especially for JS/TS web backends and frontends heading toward merge or release.
What do I get? / Deliverables
You get a scope-aware security review pass that surfaces critical calls, misconfigurations, and missing guards aligned to your detected languages and frameworks.
- Scoped security findings tied to flagged APIs, framework misconfigurations, and missing auth or method guards
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Ship because the skill operationalizes pre-release and pre-merge vulnerability hunting with explicit pattern catalogs rather than casual code reading. Security subphase is where structured scope resolution plus critical-API checklists belong before you trust production exposure.
Where it fits
While adding a new Express endpoint, flag missing body limits and permissive CORS before the feature branch grows.
Pre-release pass on authentication flows and Server Actions that mutate user data.
Augment a PR review with explicit JS/TS critical API hits instead of generic style comments.
How it compares
Pattern-guided review skill for your repo diffs, not a hosted vulnerability scanner MCP or dependency bot replacement.
Common Questions / FAQ
Who is security-review for?
Indie developers and tiny teams using Copilot-class agents on JavaScript/TypeScript web apps who need structured appsec review during ship prep.
When should I use security-review?
In Ship/security before release or merge; in Build/backend while implementing Express or Next.js API routes; and in Ship/review when a PR touches auth, CORS, or user-controlled HTML.
Is security-review safe to install?
The skill is review guidance; installing the parent bundle should be vetted via the Security Audits panel on this Prism page—do not treat pattern lists as proof of a clean repo.
SKILL.md
READMESKILL.md - Security Review
# Language-Specific Vulnerability Patterns Load the relevant section during Step 1 (Scope Resolution) after identifying languages. --- ## JavaScript / TypeScript (Node.js, React, Next.js, Express) ### Critical APIs/calls to flag ```js eval() // arbitrary code execution Function('return ...') // same as eval child_process.exec() // command injection if user input reaches it fs.readFile // path traversal if user controls path fs.writeFile // path traversal if user controls path ``` ### Express.js specific ```js // Missing helmet (security headers) const app = express() // Should have: app.use(helmet()) // Body size limits missing (DoS) app.use(express.json()) // Should have: app.use(express.json({ limit: '10kb' })) // CORS misconfiguration app.use(cors({ origin: '*' })) // too permissive app.use(cors({ origin: req.headers.origin })) // reflects any origin // Trust proxy without validation app.set('trust proxy', true) // only safe behind known proxy ``` ### React specific ```jsx <div dangerouslySetInnerHTML={{ __html: userContent }} /> // XSS <a href={userUrl}>link</a> // javascript: URL injection ``` ### Next.js specific ```js // Server Actions without auth export async function deleteUser(id) { // missing: auth check await db.users.delete(id) } // API Routes missing method validation export default function handler(req, res) { // Should check: if (req.method !== 'POST') return res.status(405) doSensitiveAction() } ``` --- ## Python (Django, Flask, FastAPI) ### Django specific ```python # Raw SQL User.objects.raw(f"SELECT * FROM users WHERE name = '{name}'") # SQLi # Missing CSRF @csrf_exempt # Only OK for APIs with token auth # Debug mode in production DEBUG = True # in settings.py — exposes stack traces # SECRET_KEY SECRET_KEY = 'django-insecure-...' # must be changed for production # ALLOWED_HOSTS ALLOWED_HOSTS = ['*'] # too permissive ``` ### Flask specific ```python # Debug mode app.run(debug=True) # never in production # Secret key app.secret_key = 'dev' # weak # eval/exec with user input eval(request.args.get('expr')) # render_template_string with user input (SSTI) render_template_string(f"Hello {name}") # Server-Side Template Injection ``` ### FastAPI specific ```python # Missing auth dependency @app.delete("/users/{user_id}") # No Depends(get_current_user) async def delete_user(user_id: int): ... # Arbitrary file read @app.get("/files/{filename}") async def read_file(filename: str): return FileResponse(f"uploads/{filename}") # path traversal ``` --- ## Java (Spring Boot) ### Spring Boot specific ```java // SQL Injection String query = "SELECT * FROM users WHERE name = '" + name + "'"; jdbcTemplate.query(query, ...); // XXE DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // Missing: dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true) // Deserialization ObjectInputStream ois = new ObjectInputStream(inputStream); Object obj = ois.readObject(); // only safe with allowlist // Spring Security — permitAll on sensitive endpoint .antMatchers("/admin/**").permitAll() // Actuator endpoints exposed management.endpoints.web.exposure.include=* # in application.properties ``` --- ## PHP ```php // Direct user input in queries $result = mysql_query("SELECT * FROM users WHERE id = " . $_GET['id']); // File inclusion include($_GET['page'] . ".php"); // local/remote file inclusion // eval eval($_POST['code']); // extract() with user input extract($_POST); // overwrites any variable // Loose comparison if ($password == "admin") {} // use === instead // Unserialize unserialize($_COOKIE['data']); // remote code execution ``` --- ## Go ```go // Command injection exec.Command("sh", "-c", userInput) // SQL injection db.Query("SELECT * FROM users WHERE name = '" + name + "'") // Path traversal filePath := filepath.Join("/uploads/", userInput) // sanitize userInput first //