agentsclimarketplace

Secure coding

Skill roodlicht/accans-sec-skills/skills/secure-coding

47 Claude skills for security tradecraft across AppSec, Pentest, Blue Team, and GRC. NL/EU regulatory-anchored. Pattern-level discipline.

Install
npx -y skills add roodlicht/accans-sec-skills --skill secure-coding

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

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 4 stars4 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

Language-agnostic secure-coding patterns — input validation, injection-safe APIs, authN/authZ, crypto, secrets, dependency hygiene. The default lens when no framework-specific skill applies.

SKILL.md

15.0 KB, ~3.6k tokens by cl100k_base, as published. Nobody here has run it

Secure Coding Standards

When to use

This skill is the substrate layer for code work. It triggers when Claude is writing or reviewing code and there's no framework-specific skill that goes deeper.

Activates on:

  • A question like "is this safe?", "review for security issues", "could someone abuse this?", "what could go wrong?".
  • New code that takes untrusted input, handles secrets, performs auth, touches crypto, or talks to external systems.
  • A patch or PR review without a sharper skill (such as django-security or api-security) active.
  • As a backstop for code generation in a language without a specific skill (Go, Rust, C#, PHP, Kotlin).

When NOT to use (handoff to sharper skills)

  • Framework-specific: Django → django-security, Rails → rails-security, Spring Boot → spring-security, Next.js → nextjs-security.
  • API design or REST/GraphQL endpoints → api-security.
  • Infrastructure: Terraform/Ansible/Pulumi → iac-security, Dockerfile or OCI → container-hardening, Kubernetes manifests → k8s-security, CI/CD workflows → cicd-hardening.
  • Vulnerability triage on dependencies → cve-triage, SBOM and provenance → supply-chain, secrets in git history → secrets-scanner.
  • Full PR review as a workflow (not just patterns) → security-review. This skill is its pattern library.

If one of the above skills applies, use that first. secure-coding remains relevant for the parts they don't cover.

Approach

Six phases. Work through them sequentially during a review. When generating code you can jump between them depending on what you're writing. Each phase has the same shape: rule → code signal (red flags to spot) → do/don't.

The phases correspond to OWASP Top 10 2021 and Proactive Controls v3, but here they are organized in the order a developer encounters them in practice.

1. Map trust boundaries

The first question with any piece of code: where does untrusted data enter, and which code runs with more privilege than the data producer?

  • Inventory trust sources. HTTP parameters, headers, cookies, file uploads, database content (previously written by an untrusted source), environment variables in multi-tenant contexts, message queues, cross-service RPC, files from object storage.
  • Separate privilege zones. Setuid binaries, service accounts, cloud IAM roles, container caps: every privilege escalation crosses a trust boundary. Code running with elevated privilege must treat input as if it were a fresh attack.
  • Data integrity at serialization boundaries. Every place you serialize (JSON, protobuf, custom binary, YAML) or deserialize is a boundary. A signature plus integrity check belongs with data that travels between trust zones (think JWT, cookies, cached computations).

Red flag — trust loss. Code that says "this comes from the database so it's safe" — unless you've also validated the write path to that database, that's an assumption. Cached untrusted data is still untrusted.

2. Input validation and output encoding

Two separate concerns that often get conflated. Validate at the boundary (parse, don't validate-after-parse); encode at the output point based on the destination context.

  • Allowlist over denylist. Validate on type, length, format, range, character class. "Anything except <script>" is a denylist and always loses to encoding tricks, Unicode homoglyphs, or new payload shapes.
  • Parse, don't validate. Where possible, convert input into a type that enforces the invariant (int, UUID, enum) instead of passing the string along with a separate validation check. See Alexis King's "Parse, don't validate".
  • Context-aware output encoding. The same string must be escaped differently in HTML body, HTML attribute, JavaScript string, URL query, CSS value, and shell argument. Use framework primitives (safe_join, template auto-escape, shlex.quote).
  • Parameterized queries for every query language. SQL via prepared statements, OS commands via arg-array instead of shell-string, LDAP via escaped filters, XPath via variable binding, templates via auto-escape mode (Jinja2 autoescape=True, ERB h(), etc.).

Red flags in code:

# SQL — string interpolation in query
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
cursor.execute("SELECT * FROM users WHERE id = " + user_id)

# Command — shell=True with user input
subprocess.Popen(f"git clone {url}", shell=True)
os.system("convert " + filename + " out.png")

# Template — raw HTML insertion
element.innerHTML = userInput        # JS/DOM
v-html="userInput"                   # Vue
dangerouslySetInnerHTML={{ __html }} # React
{{ user.bio | safe }}                # Jinja2 with | safe on untrusted

Safe variants:

# SQL
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))       # psycopg2
db.query("SELECT * FROM users WHERE id = $1", userID)                 # Go
PreparedStatement s = conn.prepareStatement("SELECT ... WHERE id = ?") # Java

# Command
subprocess.run(["git", "clone", url], check=True)                     # no shell
child_process.execFile("git", ["clone", url])                         # Node

# Template — keep auto-escape on by default, deliberately disable only for trusted data

3. Identity: authentication, sessions, authorization

No hand-rolled auth. Use vetted frameworks (Spring Security, Django auth, auth.js, Devise, Keycloak, Auth0). If you do build something yourself, build it around a vetted primitive only.

  • Password hashing: argon2id (preferred), scrypt, or bcrypt. Never MD5, SHA-1, SHA-256 without a KDF, no PBKDF2 with low iteration counts. Use library defaults; custom parameters are a red flag.
  • MFA from day one for admin and privileged accounts. TOTP, WebAuthn/passkeys, push-based. SMS is a legacy fallback, not primary.
  • Sessions: signed, HttpOnly, Secure, SameSite=Lax or Strict, short TTL, rotate on privilege change. No session ID in URL.
  • Authorization per resource, not per route. IDOR (Insecure Direct Object Reference) happens when /api/documents/123 only checks authentication and not whether the actor may see 123. Check ownership or role on every lookup path.
  • Fail-closed default. No access unless explicitly granted. Middleware that returns "allow" on an unknown route is a bug.

Red flags:

# Password handling
hashlib.md5(password.encode()).hexdigest()
hashlib.sha256(password.encode()).hexdigest()    # no salt, no KDF
bcrypt.hashpw(password, bcrypt.gensalt(4))       # cost factor too low

# Session
document.cookie = "sid=" + sessionId             # JS can read it → XSS steals
session.permanent = True                         # without TTL set

# AuthZ
@app.route("/api/documents/<id>")
def get_doc(id):
    return Document.objects.get(id=id)           # no ownership check

# Generic "is logged in" as the only check
if (user.isAuthenticated()) { return adminPanel }

4. Secrets, keys, crypto

Implementing crypto yourself is the classic foot-gun. Use high-level APIs. For secrets: never in source, ideally in a vault, env-vars are acceptable as a secondary path.

  • Secrets management hierarchy. Vault (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault) > platform-provided injection (K8s secret, ECS task role) > env-var on host > .env file outside git. Never in source, never in logs, never in error messages.
  • Key rotation + per-environment separation. Dev/staging/prod never share keys. Rotate on a schedule and on suspicion of leak. Keep the previous key briefly to allow graceful rotation.
  • Symmetric crypto: AES-GCM or ChaCha20-Poly1305. ECB never. CBC only with verified HMAC. Unique nonce per message.
  • Asymmetric: Ed25519 for signatures, X25519 for key exchange, RSA ≥ 3072 bits as legacy. MD5/SHA-1 are dead for signatures.
  • TLS 1.2+ minimum, 1.3 preferred. Certificate validation always on. verify=False in requests/curl is a staging hack, not a production config.
  • Randomness: os.urandom / crypto.randomBytes / SecureRandom. Never Math.random() / random.random() for security purposes (tokens, IDs, nonces).

Red flags:

# Hardcoded secrets
const API_KEY = "sk-proj-..."
db_password = "Welcome2024!"
# AWS / GitHub / Slack tokens in source → caught with gitleaks or trufflehog

# Crypto wrong
cipher = AES.new(key, AES.MODE_ECB)              # ECB
requests.get(url, verify=False)                  # TLS validation off
token = str(random.random())                     # not crypto-safe
hashlib.sha1(data).hexdigest()                   # for signatures/integrity

# Key management
KEY = "hardcoded-32-byte-string-right-here"       # also as env-var fallback

5. Robustness: errors, deserialization, logging

What happens when something goes wrong? Fail closed, no sensitive data in errors, no dangerous deserialization, structured logging without secrets.

  • Exception handling: catch specifically, not generically. catch (Exception e) { } (Java/C#) or except: pass (Python) masks bugs that may be security-relevant. Log the error, return a generic message to the user.
  • No stack traces or internal paths to the client. Production error pages show request-id, not /home/app/lib/.../db.py line 47 in _execute.
  • Deserialization of untrusted data is RCE-prone with native formats. Java ObjectInputStream, Python pickle.loads, PHP unserialize, Ruby Marshal.load, YAML yaml.load (without SafeLoader), .NET BinaryFormatter. Use JSON, protobuf, or msgpack with schema validation.
  • Signed integrity for cross-boundary data. JWTs must be validated with the expected algorithm (prevent alg: none and algorithm confusion). Cookies that encode server state are signed with HMAC.
  • Logging hygiene. Never log passwords, tokens, card numbers, API keys, PII (BSN, full email, etc.). Mask at the source, not at the log pipeline. Do log security events: auth failures, authz denials, admin actions, rate-limit hits.

Red flags:

# Swallowed exceptions
try: risky()
except: pass
catch (Exception e) { /* empty */ }

# Dangerous deserialization
pickle.loads(request.body)
yaml.load(user_input)                            # without Loader=SafeLoader
ObjectInputStream ois = new ObjectInputStream(sock.getInputStream())

# JWT
jwt.decode(token, key, algorithms=None)          # accept any alg
jwt.decode(token, None, options={"verify_signature": False})

# Logging
logger.info(f"Login for {user.email} with password {password}")
logger.error(f"Payment {card_number} failed")

6. Dependencies and runtime hygiene

Inherited vulnerabilities through libraries are the largest share of modern exploits (OWASP A06). Treat this as a first-class concern.

  • Pin. package-lock.json / poetry.lock / Gemfile.lock / go.sum committed in git. Transitive dep versions must be reproducible.
  • Generate an SBOM. CycloneDX or SPDX via cyclonedx-bom, syft, sbom-tool. In CI, every build. See the supply-chain skill for provenance.
  • Vulnerability scanning. Dependabot/Renovate for updates, osv-scanner or grype for scans, Snyk/Mend for enterprise. Scan on a per-PR basis, not just nightly.
  • Typosquatting defence. Look critically at new dependencies: author, age, download trend, scoped name. Consider an internal mirror for critical packages.
  • Runtime minimalism. Container does not run as root. Filesystem read-only where possible. Seccomp/AppArmor defaults on. Egress network policies. See container-hardening and k8s-security for depth.
  • Update cadence. Critical CVE in a direct dependency: patch within days. In a transitive: risk-weighted via cve-triage (reachable path plus EPSS).

Red flags:

# requirements.txt without version pin
requests
flask

# package.json with caret on everything (^) → auto-drift
"dependencies": { "lodash": "^4.0.0" }

# Dockerfile
FROM node:latest           # latest tag = unreproducible
USER root                  # or no USER directive
ADD http://... /app/       # ADD with URL bypasses integrity

# Runtime
process.env.NODE_ENV not "production" in prod
DEBUG=True in production config (Django, Flask)

Output

When this skill is used for a code review or scan, it produces a structured report. During code generation the skill works "silently": it influences what you write but produces no separate output.

Report structure for review:

Findings per phase:
  1. Trust boundaries: <ok | issues: ...>
  2. Input/output: <ok | issues with file:line>
  3. Identity: <ok | issues with file:line>
  4. Secrets/crypto: <ok | issues with file:line>
  5. Robustness: <ok | issues with file:line>
  6. Dependencies: <ok | issues with versions>

Per issue:
- Phase: <1–6>
- Location: <file:line>
- Classification: <CWE-ID, OWASP A0x>
- Severity: <blocker | high | medium | low>
- Pattern: <short name, e.g. "SQL string concat", "pickle.loads", "verify=False">
- Fix: <concrete suggestion, ideally with code alternative>
- Handoff: <if applicable: use <skill-id> for deeper review>

Overall conclusion: <blocker count, overall verdict>

Always tie issues to a CWE-ID where possible — that's the language tools (SAST, CI, issue trackers) speak. Use only CWE numbers you can verify; mark with [verify: CWE] when in doubt (see verification-loop Layer 2).

References

Categories

  • core
  • appsec

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,984. 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.