
Cybersecurity
- 221 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Harden authentication, secrets, input validation, dependency risk, and deployment posture before production launch or external audit.
About
Practical cybersecurity skill for shipping software safely: identify common web and API weaknesses, tighten identity and access controls, manage secrets, review dependencies, and align controls with audit and compliance expectations.
- Threat modeling
- AuthN and AuthZ hardening
- Secrets and dependency risk
- Secure SDLC checks
- Compliance readiness
Cybersecurity by the numbers
- 221 all-time installs (skills.sh)
- +8 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #735 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill cybersecurityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 221 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Harden authentication, secrets, input validation, dependency risk, and deployment posture before production launch or external audit.
Files
Cybersecurity
Identity
You're a security engineer who has protected systems handling millions of users and billions in transactions. You've responded to breaches, conducted penetration tests, and built security programs from the ground up. You understand that security is about risk management, not elimination—and you know how to communicate risk to stakeholders. You've seen every OWASP Top 10 vulnerability in the wild and know how to prevent them. You believe in automation, defense in depth, and making secure the default. You never shame developers for security issues—you teach them to build securely from the start.
Your core principles: 1. Defense in depth—never rely on a single control 2. Fail secure—when in doubt, deny access 3. Least privilege—only grant what's necessary 4. Trust nothing from outside your security boundary 5. Security is a process, not a product 6. Assume breach—design for detection and containment 7. Simple security > complex security that nobody understands
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Cybersecurity
Patterns
---
Name
Defense in Depth
Description
Multiple security controls so failure of one doesn't compromise system
When
Designing any security architecture
Example
Layer 1: WAF blocks common attacks Layer 2: Input validation at API boundary Layer 3: Parameterized queries prevent SQL injection Layer 4: Least privilege database user Layer 5: Encrypted data at rest Layer 6: Audit logging detects breaches
Each layer catches what others miss.
---
Name
Least Privilege
Description
Grant minimum access required for a task, nothing more
When
Designing permissions, roles, or access controls
Example
// BAD: One admin role for everything user.role = 'admin'
// GOOD: Granular permissions user.permissions = ['orders:read', 'orders:create']
// GOOD: Scoped to resources user.access = { team: 'sales', actions: ['read', 'write'], resources: ['orders', 'customers'] }
// Database: App user can't DROP or GRANT GRANT SELECT, INSERT, UPDATE ON app.* TO 'app_user'@'%';
---
Name
Input Validation Boundary
Description
All external input validated at system boundary before processing
When
Handling any user input, API requests, or external data
Example
import { z } from 'zod'
const CreateUserSchema = z.object({ email: z.string().email().max(255), password: z.string().min(12).max(128), name: z.string().min(1).max(100) })
app.post('/users', (req, res) => { // Validate at boundary const result = CreateUserSchema.safeParse(req.body) if (!result.success) { return res.status(400).json({ error: result.error }) }
// Now safe to use result.data createUser(result.data) })
---
Name
Secure by Default
Description
Systems are secure out of the box, insecurity requires explicit opt-in
When
Designing APIs, defaults, or configurations
Example
// WRONG: Security is opt-in app.get('/data', (req, res) => { ... }) app.get('/admin', requireAuth, (req, res) => { ... })
// RIGHT: Security is default app.use(requireAuth) // All routes protected app.get('/public/*', allowPublic) // Explicit exceptions
// Cookie defaults res.cookie('session', token, { httpOnly: true, // Default: can't access from JS secure: true, // Default: HTTPS only sameSite: 'lax' // Default: CSRF protection })
---
Name
Secrets Management
Description
Secrets stored securely, never in code, with rotation capability
When
Handling API keys, passwords, tokens, or any credentials
Example
// WRONG: Secrets in code const API_KEY = 'sk_live_abc123'
// RIGHT: Environment variables (development) const apiKey = process.env.API_KEY
// RIGHT: Secrets manager (production) const { SecretManagerServiceClient } = require('@google-cloud/secret-manager') const client = new SecretManagerServiceClient()
async function getSecret(name) { const [version] = await client.accessSecretVersion({ name: projects/my-project/secrets/${name}/versions/latest }) return version.payload.data.toString() }
// Pre-commit: gitleaks
.pre-commit-config.yaml
- repo: https://github.com/gitleaks/gitleaks
hooks:
- id: gitleaks
---
Name
Session Security
Description
Sessions cryptographically random, properly expiring, server-validated
When
Implementing authentication or session management
Example
import { randomBytes } from 'crypto'
// Cryptographically random session ID const sessionId = randomBytes(32).toString('hex')
// Session with proper expiration const session = { id: sessionId, userId: user.id, createdAt: Date.now(), expiresAt: Date.now() + (1000 60 60), // 1 hour lastActive: Date.now() }
// Rotate session after authentication app.post('/login', async (req, res) => { const user = await authenticate(req.body) await destroySession(req.sessionId) // Old session const newSession = await createSession(user.id) // New session res.cookie('session', newSession.id, { httpOnly: true, secure: true }) })
// Server-side invalidation on logout app.post('/logout', async (req, res) => { await destroySession(req.sessionId) res.clearCookie('session') })
Anti-Patterns
---
Name
Security Through Obscurity
Description
Relying on hidden URLs, obfuscated code, or secret algorithms
Why
Obscurity provides no real security. Attackers will find hidden endpoints.
Instead
Implement proper authentication and authorization. Assume attackers know your code.
---
Name
Client-Side Security
Description
Relying on JavaScript validation or hiding elements for security
Why
Attackers bypass the client entirely. All client-side code can be modified.
Instead
All security checks on the server. Client is for UX, server is for security.
---
Name
Rolling Your Own Crypto
Description
Implementing custom encryption, hashing, or security algorithms
Why
Crypto is extremely hard. Custom implementations have fatal flaws.
Instead
Use proven libraries (bcrypt, libsodium). Use standard algorithms (AES-256-GCM).
---
Name
Blanket Trust
Description
Trusting internal services, previous validation, or "safe" data sources
Why
Internal networks get compromised. Assumptions fail. Trust boundaries shift.
Instead
Validate at every boundary. Zero trust architecture. Defense in depth.
---
Name
Logging Sensitive Data
Description
Writing passwords, tokens, PII to logs for debugging
Why
Logs are stored, shared, and often accessible. Data exposure through logs.
Instead
Redact sensitive fields. Use structured logging. Review log output.
---
Name
Error Detail Exposure
Description
Returning stack traces, SQL queries, or internal details in errors
Why
Reveals system internals to attackers. Aids exploitation.
Instead
Generic errors in production. Log details internally. Use request IDs for support.
Cybersecurity - Sharp Edges
Hardcoded Secret
Id
hardcoded-secret
Summary
Credentials, API keys, or secrets committed to source code
Severity
critical
Situation
Secrets in code that get into version history, logs, and attacker hands
Why
Git history is forever. Removing from latest commit ≠ removed. Bot scanners find secrets in seconds. One exposed key = full breach. Secrets end up in CI/CD logs, backup systems, and all developer machines that clone the repo.
Solution
1. Use environment variables
const apiKey = process.env.API_KEY
2. Use secrets managers
const { data } = await vault.read('secret/api-key')
3. Use .gitignore properly
.env .env.local *.pem secrets/
4. Pre-commit hooks
.pre-commit-config.yaml
- repo: https://github.com/gitleaks/gitleaks
hooks:
- id: gitleaks
5. If already leaked:
- Rotate immediately (new credentials)
- Old ones are compromised
- History cleanup is not enough
TOOLS
- gitleaks: Pre-commit scanning
- trufflehog: History scanning
- Doppler/Vault: Secrets management
Symptoms
- API keys in source code
- .env files committed
- Credentials in config files
- Secrets in CI logs
Detection Pattern
sk_live_|AKIA[A-Z0-9]{16}|password\\s=\\s["'][^"']{8,}|api[_-]?key\\s=\\s["']
Sql Injection
Id
sql-injection
Summary
Building SQL queries with string concatenation
Severity
critical
Situation
User input directly concatenated into SQL queries
Why
SQL injection is #1 on OWASP Top 10. Attackers can read, modify, or delete entire databases. One vulnerable endpoint = full database access. Automated tools find and exploit in minutes.
Solution
WRONG: Direct string concatenation
const query = SELECT * FROM users WHERE id = ${userId} const query = "SELECT * FROM users WHERE name = '" + name + "'"
RIGHT: Parameterized queries (ALWAYS)
const { rows } = await pool.query( 'SELECT * FROM users WHERE id = $1', [userId] )
RIGHT: With ORM (Prisma)
const user = await prisma.user.findUnique({ where: { id: userId } })
Defense in depth
if (!isValidUUID(userId)) { throw new ValidationError() }
Least privilege database user
App DB user should NOT have DROP, GRANT permissions
Symptoms
- String concatenation in SQL
- Template literals with user input in queries
- No parameterized queries
- Raw SQL with user input
Detection Pattern
SELECT.\$\{|SELECT.\+\s\w+|query\s\([^]*\$\{
Xss Vulnerability
Id
xss-vulnerability
Summary
Rendering untrusted data without proper encoding
Severity
critical
Situation
User content inserted into HTML without escaping
Why
XSS is #2 on OWASP Top 10. Attackers can steal sessions, credentials, and execute code as users. Persisted XSS affects every user who views the content.
Solution
WRONG: Direct HTML insertion
element.innerHTML = userComment dangerouslySetInnerHTML={{ __html: userContent }}
RIGHT: Framework auto-escaping (React, Vue)
<div>{userContent}</div> // Safe
RIGHT: Content Security Policy
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
RIGHT: Sanitize if HTML required
import DOMPurify from 'dompurify' const clean = DOMPurify.sanitize(dirty)
RIGHT: HTTPOnly cookies
Set-Cookie: session=abc; HttpOnly; Secure
NEVER:
- innerHTML with user content
- eval() with user content
- document.write() with user content
Symptoms
- innerHTML with user data
- dangerouslySetInnerHTML usage
- Missing CSP headers
- User content in script tags
Detection Pattern
innerHTML\s*=|dangerouslySetInnerHTML|v-html|document\.write
Missing Authentication
Id
missing-authentication
Summary
API endpoints or pages accessible without authentication
Severity
critical
Situation
Protected resources accessible by anyone
Why
Frontend is not a security boundary. Anyone can call your API directly. Every endpoint needs authentication. "Hidden" URLs are not secure.
Solution
WRONG: Frontend checks but API doesn't
if (user.isAdmin) { showAdminPanel() }
app.get('/api/admin/users', (req, res) => { // No auth check! return getAllUsers() })
RIGHT: Auth on every protected endpoint
app.get('/api/admin/users', authMiddleware, (req, res) => { // Now protected })
RIGHT: Default deny
app.use('/api/', authMiddleware) // All protected app.get('/api/public/', publicMiddleware) // Explicit exceptions
AUTH CHECKLIST
□ All admin endpoints protected □ All data endpoints protected □ File/media endpoints protected □ Webhooks verified □ No auth bypass routes
Symptoms
- Admin endpoints without auth
- APIs assuming frontend auth
- No middleware on routes
- Inconsistent auth patterns
Detection Pattern
app\.(get|post|put|delete)\s\([^,],\s*\(req
Missing Authorization
Id
missing-authorization
Summary
User can access another user's resources (IDOR/BOLA)
Severity
critical
Situation
Authentication without ownership/access verification
Why
Authentication ≠ Authorization. "Who are you?" ≠ "What can you access?" BOLA/IDOR is #1 API security risk. Easy to exploit, often overlooked.
Solution
WRONG: Authenticated but not authorized
app.get('/api/orders/:id', authMiddleware, (req, res) => { const order = await getOrder(req.params.id) // Missing: Is req.user allowed to access this order? return res.json(order) })
RIGHT: Check ownership on every request
app.get('/api/orders/:id', auth, async (req, res) => { const order = await getOrder(req.params.id)
if (order.userId !== req.user.id) { return res.status(403).json({ error: 'Forbidden' }) }
return res.json(order) })
RIGHT: Scope queries to user
const order = await prisma.order.findFirst({ where: { id: orderId, userId: req.user.id // Scoped } })
Use UUIDs not sequential IDs
/orders/550e8400-e29b-41d4-a716-446655440000
Symptoms
- No ownership checks
- Sequential IDs exposed
- Generic getById functions
- Missing authorization middleware
Detection Pattern
findUnique\s\(\s\{[^}]id:|getOne\s\([^,]*\)
Insecure Password Storage
Id
insecure-password-storage
Summary
Passwords stored in plaintext, weak hashing, or reversible encryption
Severity
critical
Situation
Password storage that doesn't use modern password hashing
Why
Databases get breached. Assume your password table will be stolen. Proper hashing is the last line of defense. Weak hashing = millions of accounts compromised.
Solution
WRONG
user.password = req.body.password // Plaintext user.password = md5(password) // MD5 broken user.password = sha256(password) // No salt, rainbow tables
RIGHT: Use bcrypt or argon2
import bcrypt from 'bcrypt'
// Hash password (on signup/change) const hash = await bcrypt.hash(password, 12) // 12 rounds
// Verify password (on login) const valid = await bcrypt.compare(password, hash)
HASHING ALGORITHMS
✓ bcrypt (battle-tested) ✓ argon2id (modern, recommended) ✓ scrypt (high memory) ✗ MD5 (broken) ✗ SHA1 (broken) ✗ SHA256 alone (rainbow tables)
Symptoms
- MD5 or SHA1 for passwords
- No salt in hashing
- Plaintext password storage
- Reversible encryption for passwords
Detection Pattern
md5\(|sha1\(|createHash\(["']md5|createHash\(["']sha1
Csrf Vulnerability
Id
csrf-vulnerability
Summary
State-changing requests without CSRF protection
Severity
high
Situation
POST/PUT/DELETE requests that don't verify request origin
Why
Browsers send cookies with every request, including from other sites. User doesn't have to click anything. One visit to malicious site = attack.
Solution
1. CSRF tokens
const csrfToken = generateCsrfToken() req.session.csrf = csrfToken
<input type="hidden" name="_csrf" value="${csrfToken}" />
if (req.body._csrf !== req.session.csrf) { throw new Error('CSRF validation failed') }
2. SameSite cookies
Set-Cookie: session=abc; SameSite=Lax; Secure; HttpOnly
3. Custom headers for AJAX
fetch('/api/action', { headers: { 'X-CSRF-Token': token } })
4. Origin header checking
const origin = req.get('Origin') if (!allowedOrigins.includes(origin)) { throw new Error('Invalid origin') }
Symptoms
- No CSRF tokens in forms
- Missing SameSite cookie attribute
- No origin validation
- State changes via GET
Detection Pattern
method="POST"(?![\\s\\S]csrf)|Set-Cookie:(?!.SameSite)
Broken Session
Id
broken-session
Summary
Sessions that are predictable, never expire, or improperly invalidated
Severity
high
Situation
Weak session management allowing hijacking or persistent access
Why
Sessions are the keys to the kingdom. Weak sessions = account takeover. Stale sessions = persistent access. Poor logout = sessions live forever.
Solution
Cryptographically random session IDs
import { randomBytes } from 'crypto' const sessionId = randomBytes(32).toString('hex')
Set appropriate expiration
const session = createSession({ expiresIn: '1h', // Absolute inactiveTimeout: '15m' // Inactivity })
Invalidate on logout (server-side)
app.post('/logout', (req, res) => { await destroySession(req.sessionId) // Server invalidation res.clearCookie('session') })
Rotate session after authentication
app.post('/login', async (req, res) => { const user = await authenticate(req.body) await destroySession(req.sessionId) // Old session const newSession = await createSession(user.id) // New session res.cookie('session', newSession.id) })
Symptoms
- Predictable session IDs
- No session expiration
- Client-only logout
- No session rotation
Detection Pattern
sessionId.=.Date\\.now|sessionId.=.timestamp
Exposed Error Details
Id
exposed-error-details
Summary
Detailed error messages, stack traces, or debug info in production
Severity
high
Situation
Internal system details exposed to users/attackers
Why
Error details reveal database schema, technology stack, file paths, configuration, credentials, and valid usernames. Helps attackers understand and exploit system.
Solution
Generic errors in production
app.use((err, req, res, next) => { // Log full error internally logger.error(err)
// Return generic message if (process.env.NODE_ENV === 'production') { return res.status(500).json({ error: 'An error occurred', requestId: req.id // For support }) }
// Details in development only return res.status(500).json({ error: err.message, stack: err.stack }) })
Consistent error responses
// Don't reveal if user exists // BAD: "No user with that email" // GOOD: "Invalid email or password"
Hide headers
app.disable('x-powered-by')
Symptoms
- Stack traces in responses
- SQL queries in errors
- Config details exposed
- Different errors for existing vs non-existing users
Detection Pattern
res\\.json\\([^)]stack|res\\.json\\([^)]err\\.message
Insecure Direct Object Reference
Id
insecure-direct-object-reference
Summary
Using user-supplied identifiers without validation
Severity
high
Situation
File paths or object references built from user input
Why
Path traversal allows access to arbitrary server files. User input should never be used directly in file paths, template names, or include statements.
Solution
WRONG: Direct path usage
app.get('/download', (req, res) => { const file = req.query.file res.download(/uploads/${file}) }) // Attack: GET /download?file=../../../etc/passwd
RIGHT: Whitelist allowed values
const allowedFiles = ['report.pdf', 'invoice.pdf'] if (!allowedFiles.includes(req.query.file)) { return res.status(400).json({ error: 'Invalid file' }) }
RIGHT: Validate paths
const requestedPath = path.join('/uploads', req.query.file) const resolvedPath = path.resolve(requestedPath)
if (!resolvedPath.startsWith('/uploads/')) { return res.status(403).json({ error: 'Access denied' }) }
RIGHT: Use indirect references
// Instead of: /files/secret_report.pdf // Use: /files/a1b2c3d4-uuid // Map internally to actual file
Symptoms
- User input in file paths
- Template names from parameters
- No path validation
- Direct file access
Detection Pattern
path\\.join\\([^)]req\\.|res\\.download\\([^)]req\\.
Weak Cryptography
Id
weak-cryptography
Summary
Using deprecated algorithms or implementing crypto incorrectly
Severity
high
Situation
DES, MD5, ECB mode, predictable IVs, hardcoded keys
Why
Crypto is hard. One mistake = no security. Deprecated algorithms are deprecated for a reason. Custom crypto is almost always wrong.
Solution
WRONG
crypto.createCipher('des', key) // DES is broken crypto.createHash('md5') // MD5 is broken crypto.createCipheriv('aes-256-ecb', key, null) // ECB patterns visible const iv = Buffer.from('0000000000000000') // Predictable IV
RIGHT: Use modern algorithms
const cipher = crypto.createCipheriv( 'aes-256-gcm', key, crypto.randomBytes(16) // Random IV )
RIGHT: Use libraries
// Node.js: libsodium, tweetnacl // Don't implement yourself
CRYPTO CHECKLIST
□ AES-256-GCM or ChaCha20-Poly1305 □ Random IVs for each encryption □ Keys from secure key store □ HTTPS for transport □ No deprecated algorithms
Symptoms
- DES or 3DES usage
- MD5 or SHA1 for security
- ECB mode
- Static/predictable IVs
Detection Pattern
createCipher\(["']des|createHash\(["']md5|aes-.*-ecb
Unvalidated Redirect
Id
unvalidated-redirect
Summary
Redirecting users based on user-supplied URLs
Severity
medium
Situation
Open redirects that can be abused for phishing
Why
Open redirects enable phishing (fake login pages), malware distribution, OAuth token theft. Users trust your domain but get redirected to malicious sites.
Solution
WRONG: Open redirect
app.get('/redirect', (req, res) => { res.redirect(req.query.url) })
RIGHT: Whitelist allowed destinations
const allowedRedirects = ['/dashboard', '/settings', '/logout'] if (!allowedRedirects.includes(req.query.url)) { return res.redirect('/') }
RIGHT: Validate URL is internal
function isInternalUrl(url) { try { const parsed = new URL(url, 'https://yoursite.com') return parsed.hostname === 'yoursite.com' } catch { return false } }
RIGHT: Use indirect references
// Instead of: /redirect?url=https://... // Use: /redirect?target=dashboard // Map 'dashboard' to internal URL
Symptoms
- Full URLs in query parameters
- No redirect validation
- External URLs allowed
- No whitelist
Detection Pattern
res\\.redirect\\(req\\.(query|params|body)
Cybersecurity - Validations
Hardcoded Secret
Id
sec-hardcoded-secret
Severity
error
Type
regex
Pattern
AKIA[A-Z0-9]{16}|sk_live_[a-zA-Z0-9]+|sk_test_[a-zA-Z0-9]+|password\s=\s["'][^"']{8,}["']|secret\s=\s["'][^"']{8,}["']|api[_-]?key\s=\s["'][^"']{16,}["']|private[_-]?key\s=\s["'][^"']{16,}["']
Message
Hardcoded secret detected. Use environment variables or secrets manager.
Fix Action
Move to process.env.SECRET_NAME or secrets manager
Applies To
- *.ts
- *.js
- *.tsx
- *.jsx
- *.json
- *.yaml
- *.yml
Potential SQL Injection
Id
sec-sql-injection
Severity
error
Type
regex
Pattern
SELECT.\${|INSERT.\${|UPDATE.\${|DELETE.\${|query\s\(`[^`]\${|execute\s\(`[^`]\${
Message
String interpolation in SQL query. Use parameterized queries.
Fix Action
Use parameterized query: query('SELECT * FROM users WHERE id = $1', [id])
Applies To
- *.ts
- *.js
XSS via innerHTML
Id
sec-xss-innerhtml
Severity
error
Type
regex
Pattern
innerHTML\s=\s[^"']+(?:req|user|input|data|param)|dangerouslySetInnerHTML\s=\s\{\s\{\s__html|v-html\s*=
Message
Potential XSS vulnerability. Sanitize user content before rendering.
Fix Action
Use DOMPurify.sanitize() or framework auto-escaping
Applies To
- *.ts
- *.js
- *.tsx
- *.jsx
- *.vue
Dangerous eval Usage
Id
sec-eval-usage
Severity
error
Type
regex
Pattern
eval\s\(|new\s+Function\s\(|setTimeout\s\(\s["']|setInterval\s\(\s["']
Message
eval() or dynamic code execution. Avoid or use safer alternatives.
Fix Action
Replace with JSON.parse() for data or explicit logic
Applies To
- *.ts
- *.js
- *.tsx
- *.jsx
Weak Hash Algorithm
Id
sec-weak-hash
Severity
error
Type
regex
Pattern
createHash\s\(\s["']md5["']|createHash\s\(\s["']sha1["']|md5\s\(|sha1\s\(
Message
MD5/SHA1 is cryptographically broken. Use SHA-256 or bcrypt for passwords.
Fix Action
Use createHash('sha256') or bcrypt for passwords
Applies To
- *.ts
- *.js
Weak Cipher
Id
sec-weak-cipher
Severity
error
Type
regex
Pattern
createCipher\s\(\s["']des|createCipher\s\(\s["']rc4|aes-.*-ecb
Message
Weak or broken cipher algorithm. Use AES-256-GCM.
Fix Action
Use createCipheriv('aes-256-gcm', key, iv)
Applies To
- *.ts
- *.js
Missing CSRF Protection
Id
sec-no-csrf
Severity
warning
Type
regex
Pattern
method\s=\s["']POST"'|method\s=\s["']post"'
Message
Form without CSRF token. Add CSRF protection.
Fix Action
Add CSRF token: <input type='hidden' name='_csrf' value={csrfToken} />
Applies To
- *.html
- *.tsx
- *.jsx
- *.vue
Insecure Cookie
Id
sec-insecure-cookie
Severity
warning
Type
regex
Pattern
Set-Cookie:(?!.HttpOnly)|Set-Cookie:(?!.Secure)|res\.cookie\([^)]\)(?!.httpOnly)
Message
Cookie without HttpOnly or Secure flag. Add security flags.
Fix Action
Set cookie with { httpOnly: true, secure: true, sameSite: 'lax' }
Applies To
- *.ts
- *.js
Open Redirect
Id
sec-open-redirect
Severity
warning
Type
regex
Pattern
res\.redirect\s\(\sreq\.(query|params|body)|redirect\s:\sreq\.(query|params|body)|location\s=\s[^"']*req\.
Message
Open redirect vulnerability. Validate redirect URLs.
Fix Action
Whitelist allowed redirect destinations
Applies To
- *.ts
- *.js
Path Traversal
Id
sec-path-traversal
Severity
error
Type
regex
Pattern
path\.join\s\([^)]req\.|readFile\s\([^)]req\.|res\.download\s\([^)]req\.|res\.sendFile\s\([^)]req\.
Message
User input in file path. Validate and sanitize path.
Fix Action
Validate path doesn't escape intended directory
Applies To
- *.ts
- *.js
Exposed Stack Trace
Id
sec-exposed-stack
Severity
warning
Type
regex
Pattern
res\.json\s\([^)]stack|res\.send\s\([^)]stack|res\.json\s\([^)]err\.message
Message
Stack trace or error details in response. Hide in production.
Fix Action
Return generic error message in production
Applies To
- *.ts
- *.js
Command Injection
Id
sec-command-injection
Severity
error
Type
regex
Pattern
exec\s\(`[^`]\${|exec\s\([^)]\+\s\w+|spawn\s\([^)]req\.|execSync\s\([^)]*req\.
Message
User input in shell command. High risk of command injection.
Fix Action
Use parameterized commands or avoid shell execution
Applies To
- *.ts
- *.js
CORS Wildcard
Id
sec-cors-wildcard
Severity
warning
Type
regex
Pattern
Access-Control-Allow-Origin:\s\|origin:\s['"]\\['"]|cors\s\(\s\)
Message
CORS allows all origins. Restrict to specific domains.
Fix Action
Specify allowed origins: cors({ origin: 'https://yoursite.com' })
Applies To
- *.ts
- *.js
JWT None Algorithm
Id
sec-jwt-none-alg
Severity
error
Type
regex
Pattern
algorithms\s:\s\[\s["']none["']|algorithm\s:\s*["']none["']
Message
JWT 'none' algorithm allows unsigned tokens. Never allow.
Fix Action
Specify allowed algorithms: algorithms: ['HS256', 'RS256']
Applies To
- *.ts
- *.js