Decide what an error tells the client and what stays server-side: no stack traces, SQL, or paths in responses, no silent suppression, and no distinction between outcomes that would reveal protected state. Use when generating HTTP, GraphQL, or RPC error handlers, exception, panic, or rescue blocks, or configuring production error pages.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add ShieldNet-360/secure-vibe --skill error-handling-security --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Error Handling Security?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/shieldnet-360-error-handling-security-secure-vibe)More formats (shields.io, HTML) on the badges page.
---
name: error-handling-security
description: "Decide what an error tells the client and what stays server-side: no stack traces, SQL, or paths in responses, no silent suppression, and no distinction between outcomes that would reveal protected state. Use when generating HTTP, GraphQL, or RPC error handlers, exception, panic, or rescue blocks, or configuring production error pages."
---
<!-- Native skill bundle for Claude Code. Generated by `secure-vibe dev regenerate`. -->
<!-- Do not edit by hand; the source of truth is skills/error-handling-security/SKILL.md. -->
# Error-Handling Security
Decide what an error tells the client and what stays server-side: no stack traces, SQL, or paths in responses, no silent suppression, and no distinction between outcomes that would reveal protected state. Use when generating HTTP, GraphQL, or RPC error handlers, exception, panic, or rescue blocks, or configuring production error pages.
## ALWAYS
- Catch exceptions at the boundary — HTTP handler, RPC method, message consumer — and decide *there* what crosses to the client and what stays server-side. Record the failure with a correlation ID under `logging-security`'s policy; do not bypass its redaction rules to attach "full context", which is how request bodies, cookies and tokens end up in logs.
- Put only client-actionable information in an external error: a stable error code, a short human-readable message, and the correlation ID. Anything the caller cannot act on belongs in the log entry that shares that ID.
- Keep responses **consistent within an error class**, and make security-equivalent outcomes externally indistinguishable. Different classes may and should differ — `400 VALIDATION_FAILED`, `401`, `403`, `409`, `429` are not a finding. What must not differ is a pair of outcomes whose distinction reveals protected state: whether an account exists, whether a record the caller may not see is present. `auth-security` owns making the login paths cost the same; this rule owns what they return.
- Disable developer error pages and detailed exception rendering in every non-development environment, and route unhandled errors through the framework's production error handler. This is a wiring decision, not the same thing as an environment variable reading `production` — the setting and its name differ per framework, and `references/framework-error-pages.md` has them.
- Render every external error through one helper, so the sanitization rules live in a single place instead of being re-derived at each handler.
- Consult `api-security` for the status code and response envelope, `logging-security` for the internal record, and `auth-security` for making two authentication failures cost the same. This skill owns one decision — what crosses the boundary.
## NEVER
- Serialize exception or debug internals into an external response: stack traces, SQL fragments and constraint names, filesystem paths, internal hostnames, dependency or framework versions.
- Silently swallow an unexpected exception — a bare `except: pass`, `catch {}`, `rescue nil`. Let it reach the nearest designated error boundary, which logs it and converts it to a sanitized response. A narrowly-typed, commented suppression of an expected condition is fine; the finding is the broad or unexplained one.
- Withhold client-actionable validation detail in order to make the API harder to explore, or smuggle server state into it. Which field failed and why is the **public contract** — that is what RFC 9457 problem details and the GraphQL `errors` array are for — and it belongs in the response. Record existence, authorization state, and SQL or schema internals are **not** the contract and do not.
## KNOWN FALSE POSITIVES
- Developer diagnostics in an explicitly local development environment that no untrusted caller can reach. The safety comes from the deployment, not from the hostname: `localhost` and `*.local` are not security boundaries, and a debug console that executes code is dangerous wherever it is reachable.
- An authenticated, authorized diagnostic or admin endpoint returning more detail than a public one. It still may not return secrets, credentials or PII — authenticating the caller does not make that data less sensitive, and a health check should answer with status, not with internals.
## Reference files
Read these only when the task calls for them.
- `references/framework-error-pages.md`
- `references/verifying-findings.md`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!