AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Auth Analyzer

skill-curiouslearner-devkit-auth-analyzer · by CuriousLearner

Review and analyze authentication and authorization patterns for security vulnerabilities.

No reviews yet
0 installs
20 views
0.0% view→install

Install

$ agentstack add skill-curiouslearner-devkit-auth-analyzer

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-curiouslearner-devkit-auth-analyzer)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
11mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Auth Analyzer? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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:

  1. 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
  1. 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
  1. Security Assessment:
  • Authentication bypass vulnerabilities
  • Authorization flaws
  • Session hijacking risks
  • Token security issues
  • Insecure password storage
  • Broken access control
  • Account enumeration
  • Brute force vulnerabilities
  1. Compliance Checking:
  • OWASP Top 10 (A01:2021 Broken Access Control)
  • NIST authentication guidelines
  • Password policy compliance
  • Session timeout requirements
  • PCI-DSS authentication requirements
  1. 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.

Versions

  • v0.1.0 Imported from the upstream source.