agentsclimarketplace

Web security checklist

Skill yuri-semenenko/ai-engineering-workspace/claude-code/.claude/skills/web-security-checklist

One engineering workflow across Claude Code, Codex, Copilot, and Gemini CLI. A portable persona canon, process skills, and safety guardrails, kept in sync by design.

Install
npx -y skills add yuri-semenenko/ai-engineering-workspace --skill web-security-checklist

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Web application security checklist — OWASP Top 10 + LLM Top 10, threat modeling (STRIDE), auth/authz, input validation, secrets, security headers, CORS, data protection, and supply-chain hygiene. Use when reviewing security, hardening a feature, threat-modeling, or before merging security-sensitive changes (auth, user input, secrets, external or LLM-derived data). Pairs with /security-review.

SKILL.md

8.4 KB, as published. Nobody here has run it

Web Security Checklist

A fast, concrete checklist for reviewing and hardening web applications. Read the relevant section for the change at hand rather than the whole file. Treat each unchecked box as a question to answer, not a box to tick blindly.

Rationalizations (read first)

Pre-written rebuttals to the excuses that precede a skipped control. If you catch yourself thinking the left column, the right column is the answer.

RationalizationRebuttal
"This endpoint is internal, no auth needed.""Internal" is a network assumption, not a guarantee. Authn + authz still apply.
"It's just an MVP, we'll harden later."Auth, secrets, and injection are table stakes, not later-work. Later rarely comes.
"Input comes from our own frontend."The frontend is not a trust boundary. The API is. Validate at the boundary.
"It's behind a login, so it's safe."Authn ≠ authz. IDOR lives exactly here — check owner/role on every resource.
"The framework auto-escapes output."Verify the sink. dangerouslySetInnerHTML, raw SQL, and template bypasses exist.

Threat modeling (start here)

Before picking defenses, spend five minutes thinking like an attacker:

  • Trust boundaries mapped (requests, file uploads, webhooks, third-party APIs, LLM output).
  • Sensitive assets identified (credentials, PII, payment data, admin actions, financial transactions).
  • STRIDE pass per boundary (Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege).
  • Abuse cases written next to use cases: "how could I misuse this?"

Pre-commit

  • No secrets in the diff (git diff --cached | grep -iE "password|secret|api_key|token").
  • .gitignore covers .env, .env.local, *.pem, *.key.
  • .env.example uses placeholder values only (no real secrets).

Authentication

  • Passwords hashed with bcrypt (≥12 rounds), scrypt, or argon2.
  • Session cookies set httpOnly, secure, sameSite: 'lax'.
  • Session lifetime bounded (reasonable max-age).
  • Rate limiting on the login endpoint (e.g. ≤10 attempts / 15 min).
  • Password reset tokens time-bounded (≤1 hour) and single-use.
  • Account lockout after repeated failures (optional, with user notice).
  • MFA available for sensitive operations (recommended).

Authorization

  • Every protected endpoint checks authentication.
  • Owner/role checked on every resource access (prevents IDOR).
  • Admin endpoints require an admin-role check.
  • API keys scoped to least privilege.
  • JWTs validated (signature, expiry, issuer).
  • Postgres/Supabase: RLS enabled on every table; server uses the least-privileged client (anon vs service-role); ownership/tenant checks not left to RLS alone in trusted server paths.

Input validation

  • All user input validated at the boundary (API routes, form handlers).
  • Validation uses allowlists, not denylists.
  • String length bounded (min/max); numeric ranges validated.
  • Email/URL/date formats validated with vetted libraries.
  • File uploads: types restricted, size capped, content verified.
  • SQL queries parameterized (no string concatenation).
  • HTML output encoded (use the framework/templating auto-escape).
  • URLs validated before redirect (prevents open redirect).
  • SSRF: outbound requests allowlisted; private/reserved IPs blocked.

Security headers

Content-Security-Policy: default-src 'self'; script-src 'self'
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0   (disabled; rely on CSP)
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()

CORS

// Restrictive (recommended)
cors({
  origin: ['https://yourdomain.com', 'https://app.yourdomain.com'],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
})

// NEVER in production:
cors({ origin: '*' })   // allows any origin

Data protection

  • Sensitive fields stripped from API responses (passwordHash, resetToken, etc.).
  • Sensitive data never logged (passwords, tokens, full card numbers).
  • PII encrypted at rest where required by regulation.
  • HTTPS for all external traffic.
  • Database backups encrypted.

Dependency & supply-chain

npm audit                          # known CVEs
npm audit fix                      # auto-fix where safe
npm audit --audit-level=critical   # gate on criticals
npx npm-check-updates              # keep current

npm audit does not catch malicious packages. Also:

  • Lockfile committed; CI installs via npm ci, not npm install.
  • New dependencies vetted (maintenance, downloads, postinstall scripts).
  • No typosquatting (e.g. cross-env vs crossenv, react-dom vs reactdom).

AI / LLM security

For any feature that calls an LLM (chatbots, summarizers, agents, RAG):

  • Model output treated as untrusted — never pass directly into eval/SQL/shell/innerHTML/file paths.
  • Assume prompt injection; enforce permissions in code, not in the system prompt.
  • Secrets, cross-user data, and full system prompts kept out of the context window.
  • Tool/agent permissions scoped; destructive or irreversible actions require user confirmation.
  • Token, rate, and recursion/loop-depth limits in place.

Error handling

// Production: generic message, no internals
res.status(500).json({
  error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' }
});

// NEVER in production:
res.status(500).json({
  error: err.message,
  stack: err.stack,   // leaks internals
  query: err.sql,     // leaks DB structure
});

OWASP Top 10 quick reference

#RiskPrevention
1Broken access controlAuthorization on every endpoint, owner checks
2Cryptographic failuresHTTPS, strong hashing, no secrets in code
3InjectionParameterized queries, input validation
4Insecure designThreat modeling, spec-driven design
5Security misconfigurationSecurity headers, least privilege, dep audit
6Vulnerable componentsnpm audit, updates, fewer third-party packages
7Identification/auth failuresStrong passwords, rate limiting, session management
8Software/data integrity failuresVerify updates/deps, signed artifacts
9Logging/monitoring failuresLog security events, keep secrets out of logs
10SSRFURL allowlists, restrict outbound requests

OWASP Top 10 for LLM quick reference

See the OWASP GenAI Security Project.

IDRiskPrevention
LLM01Prompt injectionDon't treat the system prompt as a boundary; enforce permissions in code
LLM02Sensitive information disclosureKeep secrets/PII out of prompts; filter outputs
LLM03Supply-chainVet models, datasets, plugins like any dependency
LLM04Data & model poisoningTrusted model sources, integrity checks, validate RAG/fine-tune data
LLM05Improper output handlingTreat output as untrusted; validate, parameterize, encode
LLM06Excessive agencyScope tool permissions; confirm destructive actions
LLM07System-prompt leakageAssume it leaks; store no secrets in it
LLM08Vector & embedding weaknessesPartition RAG embeddings per user; validate documents before indexing
LLM09MisinformationGround answers in citations; verify critical claims; keep a human in the loop
LLM10Unbounded consumptionLimit tokens, rate, and loop/recursion depth

Done when

You ran the change through the relevant sections above (not just skimmed them), no Critical or High finding is left open, and you can name what you verified — authz checks exercised, inputs rejected at the boundary, secrets absent from diff and logs. "Looks secure" is not evidence; an unanswered box is unfinished work.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.