Install
$ agentstack add skill-curiouslearner-devkit-auth-analyzer ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Auth Analyzer Skill
Review and analyze authentication and authorization patterns for security vulnerabilities.
Instructions
You are an authentication and authorization security expert. When invoked:
- Analyze Authentication Mechanisms:
- Password security and hashing
- Session management
- Token-based authentication (JWT, OAuth)
- Multi-factor authentication (MFA)
- Single Sign-On (SSO)
- API key authentication
- Biometric authentication
- Review Authorization Patterns:
- Role-Based Access Control (RBAC)
- Attribute-Based Access Control (ABAC)
- Access Control Lists (ACL)
- Permission hierarchies
- Resource ownership checks
- Privilege escalation prevention
- Security Assessment:
- Authentication bypass vulnerabilities
- Authorization flaws
- Session hijacking risks
- Token security issues
- Insecure password storage
- Broken access control
- Account enumeration
- Brute force vulnerabilities
- Compliance Checking:
- OWASP Top 10 (A01:2021 Broken Access Control)
- NIST authentication guidelines
- Password policy compliance
- Session timeout requirements
- PCI-DSS authentication requirements
- Generate Report: Provide detailed security analysis with remediation guidance
Authentication Patterns
Password Authentication
Secure Password Hashing
// ✅ GOOD - Using bcrypt
const bcrypt = require('bcrypt');
async function hashPassword(password) {
const saltRounds = 12; // Cost factor
return await bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// ✅ GOOD - Using Argon2 (recommended)
const argon2 = require('argon2');
async function hashPassword(password) {
return await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536, // 64 MiB
timeCost: 3,
parallelism: 4
});
}
async function verifyPassword(password, hash) {
return await argon2.verify(hash, password);
}
Insecure Patterns
// ❌ BAD - Plain text storage
user.password = password;
// ❌ BAD - Weak hashing (MD5, SHA1)
const crypto = require('crypto');
const hash = crypto.createHash('md5').update(password).digest('hex');
// ❌ BAD - No salt
const hash = crypto.createHash('sha256').update(password).digest('hex');
// ❌ BAD - Reversible encryption
const cipher = crypto.createCipher('aes-256-cbc', key);
const encrypted = cipher.update(password, 'utf8', 'hex');
Session Management
Secure Session Implementation
// ✅ GOOD - Secure session configuration
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET, // Strong, random secret
name: 'sessionId', // Don't use default 'connect.sid'
resave: false,
saveUninitialized: false,
cookie: {
secure: true, // HTTPS only
httpOnly: true, // Prevent XSS access
maxAge: 3600000, // 1 hour
sameSite: 'strict', // CSRF protection
domain: '.example.com'
},
rolling: true, // Refresh on activity
genid: () => {
return crypto.randomBytes(32).toString('hex');
}
}));
Session Security Issues
// ❌ BAD - Insecure session
app.use(session({
secret: 'keyboard cat', // Weak secret
cookie: {
secure: false, // Works on HTTP
httpOnly: false, // Accessible via JavaScript
maxAge: 86400000 * 30 // 30 days (too long)
}
}));
// ❌ BAD - No session regeneration after login
app.post('/login', async (req, res) => {
const user = await authenticate(req.body);
req.session.userId = user.id; // Session fixation vulnerability
res.json({ success: true });
});
// ✅ GOOD - Regenerate session after login
app.post('/login', async (req, res) => {
const user = await authenticate(req.body);
req.session.regenerate((err) => {
if (err) return res.status(500).json({ error: 'Session error' });
req.session.userId = user.id;
res.json({ success: true });
});
});
JWT Authentication
Secure JWT Implementation
// ✅ GOOD - Secure JWT
const jwt = require('jsonwebtoken');
function generateToken(user) {
return jwt.sign(
{
userId: user.id,
email: user.email,
role: user.role
},
process.env.JWT_SECRET, // Strong secret (256+ bits)
{
expiresIn: '15m', // Short expiration
issuer: 'example.com',
audience: 'example.com',
algorithm: 'HS256' // Or RS256 for asymmetric
}
);
}
function generateRefreshToken(user) {
return jwt.sign(
{ userId: user.id },
process.env.REFRESH_TOKEN_SECRET,
{
expiresIn: '7d',
algorithm: 'HS256'
}
);
}
function verifyToken(token) {
try {
return jwt.verify(token, process.env.JWT_SECRET, {
issuer: 'example.com',
audience: 'example.com',
algorithms: ['HS256'] // Prevent algorithm confusion
});
} catch (error) {
throw new Error('Invalid token');
}
}
// Middleware
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const user = verifyToken(token);
req.user = user;
next();
} catch (error) {
return res.status(403).json({ error: 'Invalid or expired token' });
}
}
JWT Security Issues
// ❌ BAD - Weak secret
const token = jwt.sign(payload, 'secret', { expiresIn: '1d' });
// ❌ BAD - No expiration
const token = jwt.sign(payload, secret);
// ❌ BAD - Long expiration
const token = jwt.sign(payload, secret, { expiresIn: '365d' });
// ❌ BAD - Algorithm not specified (algorithm confusion attack)
jwt.verify(token, secret);
// ❌ BAD - Sensitive data in JWT
const token = jwt.sign({
userId: user.id,
password: user.password, // Never include sensitive data
ssn: user.ssn
}, secret);
// ❌ BAD - No signature verification
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64'));
// Using unverified payload
OAuth 2.0 / OpenID Connect
Secure OAuth Flow
// ✅ GOOD - OAuth implementation
const passport = require('passport');
const OAuth2Strategy = require('passport-oauth2');
passport.use(new OAuth2Strategy({
authorizationURL: 'https://provider.com/oauth/authorize',
tokenURL: 'https://provider.com/oauth/token',
clientID: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
callbackURL: 'https://example.com/auth/callback',
state: true, // CSRF protection
pkce: true // PKCE for added security
},
async function(accessToken, refreshToken, profile, done) {
try {
let user = await User.findOne({ oauthId: profile.id });
if (!user) {
user = await User.create({
oauthId: profile.id,
email: profile.email,
name: profile.name
});
}
return done(null, user);
} catch (error) {
return done(error);
}
}
));
// Authorization endpoint
app.get('/auth/oauth',
passport.authenticate('oauth2')
);
// Callback
app.get('/auth/callback',
passport.authenticate('oauth2', { failureRedirect: '/login' }),
(req, res) => {
res.redirect('/dashboard');
}
);
Authorization Patterns
Role-Based Access Control (RBAC)
Secure RBAC Implementation
// ✅ GOOD - RBAC implementation
const roles = {
user: ['read:own', 'write:own'],
moderator: ['read:own', 'write:own', 'read:any', 'delete:any'],
admin: ['*'] // All permissions
};
function hasPermission(userRole, permission) {
const userPermissions = roles[userRole] || [];
return userPermissions.includes('*') || userPermissions.includes(permission);
}
// Middleware
function requirePermission(permission) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Not authenticated' });
}
if (!hasPermission(req.user.role, permission)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}
// Usage
app.delete('/posts/:id',
authenticateToken,
requirePermission('delete:any'),
deletePost
);
Authorization Issues
// ❌ BAD - Client-side authorization only
// Frontend
if (user.role === 'admin') {
showAdminPanel();
}
// Backend has no checks - insecure!
// ❌ BAD - Trusting client-provided role
app.post('/admin/users', (req, res) => {
if (req.body.isAdmin) { // Attacker can set this
// Admin operation
}
});
// ❌ BAD - No ownership check
app.delete('/posts/:id', async (req, res) => {
await Post.delete(req.params.id); // Any user can delete any post
});
// ✅ GOOD - Proper ownership check
app.delete('/posts/:id', authenticateToken, async (req, res) => {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
// Check ownership or admin role
if (post.authorId !== req.user.id && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Not authorized' });
}
await post.delete();
res.json({ success: true });
});
Attribute-Based Access Control (ABAC)
// ✅ GOOD - ABAC implementation
function canAccessResource(user, resource, action) {
const rules = [
// Owner can do anything with their resources
{
match: (u, r, a) => r.ownerId === u.id,
allow: ['read', 'write', 'delete']
},
// Premium users can read any public resource
{
match: (u, r, a) => u.subscription === 'premium' && r.isPublic,
allow: ['read']
},
// Admins can do anything
{
match: (u, r, a) => u.role === 'admin',
allow: ['*']
}
];
for (const rule of rules) {
if (rule.match(user, resource, action)) {
if (rule.allow.includes('*') || rule.allow.includes(action)) {
return true;
}
}
}
return false;
}
// Middleware
function requireAccess(action) {
return async (req, res, next) => {
const resource = await loadResource(req.params.id);
if (!canAccessResource(req.user, resource, action)) {
return res.status(403).json({ error: 'Access denied' });
}
req.resource = resource;
next();
};
}
Usage Examples
@auth-analyzer
@auth-analyzer src/auth/
@auth-analyzer --check-passwords
@auth-analyzer --check-sessions
@auth-analyzer --check-jwt
@auth-analyzer --check-authorization
@auth-analyzer --report
Security Analysis Report Format
# Authentication & Authorization Security Analysis
**Application**: E-Commerce Platform
**Analysis Date**: 2024-01-15
**Analyzer**: Auth Security Scanner v3.0
---
## Executive Summary
🔴 **CRITICAL SECURITY ISSUES FOUND**
**Total Issues**: 18
- Critical: 5
- High: 7
- Medium: 4
- Low: 2
**OWASP Category**: A01:2021 – Broken Access Control
**Immediate Actions Required**: 5 critical authentication flaws need fixing
---
## Critical Issues (5)
### 🔴 Passwords Stored with Weak Hashing (MD5)
**Severity**: Critical (CVSS 9.1)
**CWE**: CWE-916 (Use of Password Hash With Insufficient Computational Effort)
**Location**: src/models/User.js:45
**Vulnerable Code**:
```javascript
// ❌ INSECURE
const crypto = require('crypto');
User.prototype.setPassword = function(password) {
this.password = crypto.createHash('md5').update(password).digest('hex');
};
User.prototype.checkPassword = function(password) {
const hash = crypto.createHash('md5').update(password).digest('hex');
return this.password === hash;
};
Vulnerability:
- MD5 is cryptographically broken
- No salt (rainbow table attacks possible)
- Fast hashing (vulnerable to brute force)
- 100M+ MD5 hashes/second on GPU
Attack Scenario:
1. Attacker gains access to database
2. Downloads password hashes
3. Uses rainbow tables or brute force
4. Cracks passwords in minutes/hours
5. Gains access to user accounts
Impact:
- All user passwords compromised
- Account takeover possible
- Credential stuffing attacks
- Privacy breach
Remediation:
// ✅ SECURE - Use Argon2id
const argon2 = require('argon2');
User.prototype.setPassword = async function(password) {
this.password = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536, // 64 MiB
timeCost: 3,
parallelism: 4
});
};
User.prototype.checkPassword = async function(password) {
try {
return await argon2.verify(this.password, password);
} catch (err) {
return false;
}
};
Migration Plan:
// Gradual migration on login
app.post('/login', async (req, res) => {
const user = await User.findOne({ email: req.body.email });
// Check old MD5 hash
if (user.password.length === 32) { // MD5 hash length
const md5Hash = crypto.createHash('md5')
.update(req.body.password)
.digest('hex');
if (user.password === md5Hash) {
// Upgrade to Argon2
await user.setPassword(req.body.password);
await user.save();
// Continue with login
}
} else {
// Use Argon2 verification
const valid = await user.checkPassword(req.body.password);
if (!valid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
}
// Login successful
});
Priority: P0 - Fix immediately
🔴 JWT Signature Not Verified
Severity: Critical (CVSS 9.8) CWE: CWE-347 (Improper Verification of Cryptographic Signature)
Location: src/middleware/auth.js:12
Vulnerable Code:
// ❌ CRITICAL VULNERABILITY
function authenticateToken(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token' });
}
// Decoding without verification!
const payload = JSON.parse(
Buffer.from(token.split('.')[1], 'base64').toString()
);
req.user = payload; // Trusting unverified data
next();
}
Vulnerability:
- JWT signature completely bypassed
- Attacker can forge any JWT
- Can impersonate any user including admins
- Trivial to exploit
Attack Example:
// Attacker creates malicious token
const fakePayload = {
userId: 1,
email: 'admin@example.com',
role: 'admin'
};
const base64Payload = Buffer.from(JSON.stringify(fakePayload)).toString('base64');
const fakeToken = `header.${base64Payload}.fakesignature`;
// Use in request
fetch('/api/admin/users', {
headers: {
'Authorization': `Bearer ${fakeToken}`
}
});
// Gains admin access!
Impact:
- Complete authentication bypass
- Privilege escalation to admin
- Full system compromise
- Data breach
Remediation:
// ✅ SECURE - Proper verification
const jwt = require('jsonwebtoken');
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const payload = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'], // Prevent algorithm confusion
issuer: 'example.com',
audience: 'example.com',
maxAge: '15m'
});
req.user = payload;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(403).json({ error: 'Invalid token' });
}
}
Priority: P0 - Fix immediately
🔴 Missing Authorization Checks
Severity: Critical (CVSS 8.8) CWE: CWE-862 (Missing Authorization)
Location: src/routes/users.js:34
Vulnerable Code:
// ❌ CRITICAL - No authorization check
app.put('/api/users/:id', authenticateToken, async (
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [CuriousLearner](https://github.com/CuriousLearner)
- **Source:** [CuriousLearner/devkit](https://github.com/CuriousLearner/devkit)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.