본문으로 건너뛰기
cccskills
무료GitHub에 공개

auth-security-reviewer

Reviews authentication and authorization implementation for session management, CSRF, cookie security, and auth flow vulnerabilities with findings, severity assessment, and fix recommendations. Use for "auth review", "session security", "CSRF protection", or "authentication audit".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md10.8 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Auth Security Reviewer

Comprehensive security review of authentication systems.

Session Security Checklist

// ❌ INSECURE Session Configuration
app.use(
  session({
    secret: "weak-secret", // Too simple
    resave: true, // Unnecessary
    saveUninitialized: true, // Creates unnecessary sessions
    cookie: {
      secure: false, // Not HTTPS-only
      httpOnly: false, // Accessible via JavaScript
      sameSite: false, // CSRF vulnerable
      maxAge: 365 * 24 * 60 * 60 * 1000, // 1 year - too long
    },
  })
);

// ✅ SECURE Session Configuration
app.use(
  session({
    secret: process.env.SESSION_SECRET, // From environment
    resave: false,
    saveUninitialized: false,
    name: "sessionId", // Don't use default 'connect.sid'
    cookie: {
      secure: true, // HTTPS only
      httpOnly: true, // No JavaScript access
      sameSite: "strict", // CSRF protection
      maxAge: 24 * 60 * 60 * 1000, // 24 hours
      domain: process.env.COOKIE_DOMAIN,
    },
    store: new RedisStore({
      client: redisClient,
      ttl: 86400,
    }),
  })
);

JWT Security Review

// ❌ INSECURE JWT Implementation
const token = jwt.sign(
  { userId: user.id },
  "weak-secret", // Hardcoded secret
  { algorithm: "HS256" } // No expiration
);

// Store in localStorage
localStorage.setItem("token", token); // XSS vulnerable

// ✅ SECURE JWT Implementation
const token = jwt.sign(
  {
    userId: user.id,
    role: user.role,
    iat: Math.floor(Date.now() / 1000),
  },
  process.env.JWT_SECRET, // Strong secret from env
  {
    algorithm: "HS256",
    expiresIn: "15m", // Short-lived
    issuer: "myapp.com",
    audience: "myapp.com",
  }
);

// Store in httpOnly cookie
res.cookie("accessToken", token, {
  httpOnly: true,
  secure: true,
  sameSite: "strict",
  maxAge: 15 * 60 * 1000,
});

// Refresh token with longer expiry
const refreshToken = jwt.sign(
  { userId: user.id, type: "refresh" },
  process.env.REFRESH_TOKEN_SECRET,
  { expiresIn: "7d" }
);

// Store refresh token in database
await storeRefreshToken(user.id, refreshToken);

CSRF Protection

// Using csurf middleware
import csrf from "csurf";

const csrfProtection = csrf({ cookie: true });

// Apply to state-changing routes
app.post("/api/transfer", csrfProtection, async (req, res) => {
  // Protected from CSRF
  await processTransfer(req.body);
  res.json({ success: true });
});

// Provide CSRF token to frontend
app.get("/api/csrf-token", csrfProtection, (req, res) => {
  res.json({ csrfToken: req.csrfToken() });
});

// Frontend usage
const csrfToken = await fetch("/api/csrf-token").then((r) => r.json());

await fetch("/api/transfer", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-CSRF-Token": csrfToken.csrfToken,
  },
  body: JSON.stringify({ amount: 100 }),
});

Password Security

// ❌ INSECURE Password Handling
const password = req.body.password;
const hash = crypto.createHash("md5").update(password).digest("hex"); // MD5 is broken
await db.user.create({ password: hash });

// ✅ SECURE Password Handling
import bcrypt from "bcrypt";

// Hashing
const saltRounds = 12; // Adjust based on security requirements
const hash = await bcrypt.hash(password, saltRounds);
await db.user.create({ passwordHash: hash });

// Verification
const isValid = await bcrypt.compare(password, user.passwordHash);

// Password requirements
function validatePassword(password: string): boolean {
  return (
    password.length >= 12 &&
    /[A-Z]/.test(password) && // Uppercase
    /[a-z]/.test(password) && // Lowercase
    /[0-9]/.test(password) && // Number
    /[^A-Za-z0-9]/.test(password) // Special char
  );
}

// Check against breached passwords
import { pwnedPassword } from "hibp";

const breachCount = await pwnedPassword(password);
if (breachCount > 0) {
  throw new Error("This password has been found in data breaches");
}

Multi-Factor Authentication

// TOTP-based MFA
import speakeasy from "speakeasy";
import qrcode from "qrcode";

// Generate secret
const secret = speakeasy.generateSecret({
  name: `MyApp (${user.email})`,
  issuer: "MyApp",
});

// Store secret
await db.user.update({
  where: { id: user.id },
  data: {
    mfaSecret: secret.base32,
    mfaEnabled: false, // Not enabled until verified
  },
});

// Generate QR code
const qrCodeUrl = await qrcode.toDataURL(secret.otpauth_url);

// Verify TOTP token
function verifyMFA(token: string, secret: string): boolean {
  return speakeasy.totp.verify({
    secret,
    encoding: "base32",
    token,
    window: 2, // Allow 2 time steps before/after
  });
}

// Backup codes
function generateBackupCodes(): string[] {
  return Array.from({ length: 10 }, () =>
    crypto.randomBytes(4).toString("hex").toUpperCase()
  );
}

Authorization Vulnerabilities

// ❌ INSECURE: Missing authorization check
app.get("/api/users/:id/profile", async (req, res) => {
  const profile = await db.user.findUnique({
    where: { id: req.params.id },
  });
  res.json(profile); // Anyone can access any profile!
});

// ✅ SECURE: Proper authorization
app.get("/api/users/:id/profile", authenticate, async (req, res) => {
  // Check if user can access this profile
  if (req.user.id !== req.params.id && req.user.role !== "ADMIN") {
    return res.status(403).json({ error: "Forbidden" });
  }

  const profile = await db.user.findUnique({
    where: { id: req.params.id },
  });
  res.json(profile);
});

// ❌ INSECURE: IDOR vulnerability
app.delete("/api/orders/:id", async (req, res) => {
  await db.order.delete({ where: { id: req.params.id } });
  res.json({ success: true });
});

// ✅ SECURE: Verify ownership
app.delete("/api/orders/:id", authenticate, async (req, res) => {
  const order = await db.order.findUnique({
    where: { id: req.params.id },
  });

  if (!order) {
    return res.status(404).json({ error: "Not found" });
  }

  if (order.userId !== req.user.id) {
    return res.status(403).json({ error: "Forbidden" });
  }

  await db.order.delete({ where: { id: req.params.id } });
  res.json({ success: true });
});

Session Fixation Prevention

// ❌ INSECURE: Session not regenerated on login
app.post("/login", async (req, res) => {
  const user = await authenticate(req.body);
  req.session.userId = user.id;
  res.json({ success: true });
});

// ✅ SECURE: Regenerate session on login
app.post("/login", async (req, res) => {
  const user = await authenticate(req.body);

  // Regenerate session to prevent fixation
  req.session.regenerate((err) => {
    if (err) return res.status(500).json({ error: "Server error" });

    req.session.userId = user.id;
    res.json({ success: true });
  });
});

// Also regenerate on privilege escalation
app.post("/admin/elevate", async (req, res) => {
  // Verify admin credentials
  await verifyAdminPassword(req.body.password);

  // Regenerate session
  req.session.regenerate((err) => {
    if (err) return res.status(500).json({ error: "Server error" });

    req.session.isAdmin = true;
    res.json({ success: true });
  });
});

Rate Limiting on Auth Endpoints

import rateLimit from "express-rate-limit";

// Strict rate limit for login
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 attempts
  message: "Too many login attempts, please try again later",
  standardHeaders: true,
  legacyHeaders: false,
  // Use IP + username for more granular limiting
  keyGenerator: (req) => `${req.ip}-${req.body.email}`,
});

app.post("/api/login", loginLimiter, async (req, res) => {
  // Login logic
});

// Even stricter for password reset
const resetLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 3,
  message: "Too many password reset attempts",
});

app.post("/api/password-reset", resetLimiter, async (req, res) => {
  // Password reset logic
});

Security Testing

// tests/auth-security.test.ts
describe("Auth Security", () => {
  describe("Session Security", () => {
    it("should set httpOnly cookie", async () => {
      const response = await request(app)
        .post("/api/login")
        .send({ email: "test@example.com", password: "password123" });

      const cookie = response.headers["set-cookie"][0];
      expect(cookie).toContain("HttpOnly");
      expect(cookie).toContain("Secure");
      expect(cookie).toContain("SameSite=Strict");
    });

    it("should regenerate session on login", async () => {
      const agent = request.agent(app);

      // Get initial session
      await agent.get("/");
      const initialCookie = agent.jar.getCookie("sessionId");

      // Login
      await agent.post("/api/login").send({
        email: "test@example.com",
        password: "password123",
      });

      const loginCookie = agent.jar.getCookie("sessionId");

      // Session ID should change
      expect(loginCookie.value).not.toBe(initialCookie.value);
    });
  });

  describe("CSRF Protection", () => {
    it("should reject requests without CSRF token", async () => {
      await request(app)
        .post("/api/transfer")
        .send({ amount: 100 })
        .expect(403);
    });

    it("should accept requests with valid CSRF token", async () => {
      const { csrfToken } = await request(app)
        .get("/api/csrf-token")
        .then((r) => r.body);

      await request(app)
        .post("/api/transfer")
        .set("X-CSRF-Token", csrfToken)
        .send({ amount: 100 })
        .expect(200);
    });
  });

  describe("Authorization", () => {
    it("should prevent IDOR attacks", async () => {
      const user1 = await createUser();
      const user2 = await createUser();

      const token1 = generateToken(user1);

      // Try to access user2's profile with user1's token
      await request(app)
        .get(`/api/users/${user2.id}/profile`)
        .set("Authorization", `Bearer ${token1}`)
        .expect(403);
    });
  });
});

Best Practices

  1. Regenerate sessions: On login and privilege changes
  2. Short-lived tokens: 15min access, 7-day refresh
  3. CSRF protection: All state-changing operations
  4. Rate limiting: Prevent brute force
  5. Secure cookies: HttpOnly, Secure, SameSite
  6. MFA: For sensitive operations
  7. Audit logs: Track authentication events

Output Checklist

  • Session configuration reviewed
  • JWT implementation secured
  • CSRF protection enabled
  • Password hashing with bcrypt
  • MFA implementation (if required)
  • Authorization checks on all endpoints
  • Session fixation prevention
  • Rate limiting on auth endpoints
  • Security tests written
  • Audit logging configured

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Audits and implements web accessibility (a11y) following WCAG 2.1 guidelines with ARIA patterns, keyboard navigation, screen reader support, and contrast checking. Use when users request "accessibility audit", "a11y review", "WCAG compliance", "screen reader support", or "keyboard navigation".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

sathishssj3/Stereix-Engine22026년 10월 4일 업데이트

Creates Architecture Decision Records documenting key technical decisions with context, alternatives considered, tradeoffs, consequences, and decision owners. Use when documenting "architecture decisions", "technical choices", "design decisions", or "ADRs".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

sathishssj3/Stereix-Engine22026년 10월 4일 업데이트

Designs multi-step agent workflows with tool usage, retry logic, state management, and budget controls. Provides orchestration diagrams, tool execution order, fallback strategies, and cost limits. Use for "AI agents", "agentic workflows", "multi-step AI", or "autonomous systems".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

sathishssj3/Stereix-Engine22026년 10월 4일 업데이트

MUST USE when user wants to 调研/research/搜索/search/查/找/look up anything on the internet — e.g. 全网调研 X / 帮我调研一下 X / 查一下 X / 搜搜 X / 看看大家怎么评价 X / X 上有什么讨论 / research this topic。 Also MUST USE when user mentions any platform or shares any URL/链接: 小红书/xiaohongshu/xhs, Twitter/推特/X, B站/bilibili, Reddit, Facebook, Instagram, V2EX, LinkedIn/领英/招聘/求职/jobs, YouTube, GitHub code search, 小宇宙播客, 雪球/股票行情, RSS feeds, or any web URL. 15 platforms, multi-backend routing (OpenCLI / per-platform CLIs / APIs). Zero config for 6 channels. Run `agent-reach doctor --json` to see which backend serves each platform right now. NOT for: 写报告/数据分析/翻译等内容加工(本 skill 只负责从互联网获取内容); 发帖/评论/点赞等写操作;已有专门 skill 的平台(先用专门 skill)。 【路由方式】SKILL.md 包含路由表和常用命令,复杂场景需按需阅读对应分类的 references/*.md。 分类:search / social (小红书/推特/B站/V2EX/Reddit/Facebook/Instagram) / career(LinkedIn) / dev(github) / web(网页/文章/RSS) / video(YouTube/B站/播客) / finance(雪球/股票)。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

sathishssj3/Stereix-Engine22026년 10월 4일 업데이트

Orchestrates multi-agent AI systems with task delegation, agent communication, shared memory, and workflow coordination. Use when users request "multi-agent system", "agent orchestration", "AI agents", "agent coordination", or "autonomous agents".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

sathishssj3/Stereix-Engine22026년 10월 4일 업데이트

Creates SLO-based alerts and operational dashboards with key charts, alert thresholds, and runbook links. Use for "alerting", "dashboards", "SLO", or "monitoring".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

sathishssj3/Stereix-Engine22026년 10월 4일 업데이트

sathishssj3의 스킬 모두 보기

이 스킬의 문제 신고