Applications that fail open, leak internals in error messages or log the wrong things hand attackers information and access while hiding the evidence defenders need. OWASP's 2025 Top 10 now gives both halves of the problem their own categories: A09:2025 Security Logging and Alerting Failures, and the new A10:2025 Mishandling of Exceptional Conditions. This guide is written for developers, AppSec engineers and platform teams who own application code and frameworks. It covers how to design exception handling that fails closed, what to return to clients, what to log and what never to log, log injection, protecting the logging pipeline itself, and how to test and measure all of it. Infrastructure log collection, retention and SIEM design are covered in the Log Management and Retention Guide and are not repeated here.
Key takeaways
- Fail closed by design. When validation, authorisation or a dependency throws, the default outcome must be "deny and roll back", never "carry on with partial state".
- Clients get a generic, structured error. Return an RFC 9457 problem details body with a correlation ID; stack traces, SQL, paths and versions stay in server-side logs.
- Log security events, not secrets. Authentication, authorisation, validation and control failures belong in logs with who, what, where and when; passwords, tokens, keys and payment data never do.
- Logs are an input channel. Encode user data written to logs (CWE-117) and treat log and error telemetry as untrusted when people, tools or AI agents read it back.
- A log nobody alerts on is not a control. Ship events off the host to a separate system, alert on defined use cases, and test that logging survives failure.
Two OWASP categories, one engineering problem
The 2025 OWASP Top 10 separates detection failures from failure handling, but in code they share the same handlers, the same exception paths and the same log calls. The table summarises what each category covers, based on the official pages.
| Aspect | A09:2025 Security Logging and Alerting Failures | A10:2025 Mishandling of Exceptional Conditions |
|---|---|---|
| Core problem | Attacks go undetected or response is slow because events are not logged, not protected or not alerted on | Software cannot prevent, detect or respond to abnormal situations, so it crashes, behaves unpredictably or fails open |
| Notable CWEs | CWE-117 Improper Output Neutralization for Logs, CWE-221, CWE-223, CWE-532 Insertion of Sensitive Information into Log File, CWE-778 Insufficient Logging | CWE-209 Generation of Error Message Containing Sensitive Information, CWE-234, CWE-274, CWE-476, CWE-636 Not Failing Securely ("Failing Open") |
| Typical outcome | Long dwell time, breaches discovered by third parties, logs that leak data or can be forged | Information disclosure, denial of service through leaked resources, corrupted transactions |
| Primary ASVS 5.0 chapter | V16 Security Logging and Error Handling (V16.1 to V16.4) | V16.5 Error Handling, plus V13.4.2 (debug modes disabled) |
A10 is new in 2025 and maps 24 CWEs. For the full lists see the OWASP Top 10 A09 Guide and the OWASP Top 10 A10 Guide; this page is the implementation companion to both.
Designing exception handling that fails closed
Failing open (CWE-636) usually comes from a catch block that logs and continues, or from a default that grants when a policy service times out. OWASP's A10 guidance is to plan for failure in advance, catch errors where they occur, roll back incomplete transactions fully rather than trying to resume them, and keep a global handler only as a backstop.
Rules for the code path
- Deny on error in security decisions: an authorisation check that throws must return "deny". Write the check so that the only path to "allow" is an explicit positive result, and make the exception path unreachable to the protected action.
- Transactional integrity: wrap multi-step operations (debit, credit, audit record) in a single transaction or a saga with compensating actions, and roll back completely on any failure. ASVS V16.5.3 requires that the application does not process a transaction despite errors from validation logic.
- Release resources in every path: use language constructs that guarantee cleanup (
trywith resources in Java,usingin C#,within Python,deferin Go). OWASP's A10 example is a file upload that leaks resources on failure until the service locks up. - Degrade safely when dependencies fail: ASVS V16.5.2 asks for patterns such as circuit breakers or graceful degradation. Degrading means serving less, not skipping checks: a fraud score that cannot be fetched should hold the payment, not approve it.
- Have a last resort handler: ASVS V16.5.4 (Level 3) requires a handler that catches all unhandled exceptions so error details still reach the logs and one request cannot take down the process.
Framework building blocks
| Framework | Central handler | Production setting to verify |
|---|---|---|
| ASP.NET Core | app.UseExceptionHandler(...) with IExceptionHandler.TryHandleAsync registered through AddExceptionHandler<T>(); AddProblemDetails() for RFC 9457 bodies | Developer exception page only in the Development environment (it shows stack trace, query string, cookies and headers). From .NET 10, logs and metrics for handled exceptions are suppressed by default; review ExceptionHandlerOptions.SuppressDiagnosticsCallback so security-relevant exceptions still reach telemetry |
| Spring MVC and Spring Boot | @RestControllerAdvice extending ResponseEntityExceptionHandler, returning ProblemDetail (Spring Framework 6) | Set server.error.include-stacktrace and server.error.include-message to never explicitly rather than relying on defaults or profiles |
| Java Servlet | <error-page> with <exception-type>java.lang.Exception in web.xml | Error page returns a generic body and logs the exception |
| ASP.NET (.NET Framework) | ExceptionLogger and ExceptionHandler replaced in WebApiConfig | <customErrors mode="RemoteOnly"> (or On) in Web.config |
| Django | Custom handler500 view and logging configuration | DEBUG = False (debug pages expose tracebacks, settings and file paths) |
See the Django Security Guide and the Node.js Security Guide.
What to return to the client
ASVS V16.5.1 requires a generic message for unexpected or security-sensitive errors, with no stack traces, queries, secret keys or tokens. The OWASP Error Handling Cheat Sheet adds that verbose errors are reconnaissance gifts: framework names, library versions and internal paths all shorten an attacker's work, and OWASP's A10 scenario describes attackers triggering database errors on purpose to tune SQL injection.
- Use RFC 9457 problem details: RFC 9457 (which obsoletes RFC 7807) defines
type,title,status,detailandinstancemembers and theapplication/problem+jsonmedia type. Its security considerations warn against exposing implementation internals such as stack dumps. - Put a correlation ID in
instanceor an extension member: support can find the server-side record; make it random, not derived from user data. - Pick honest status codes: 4xx for client-caused errors (unauthorised, too large, invalid), 5xx only when the server cannot fulfil the request. A 5xx burst for one input pattern often means probing.
- Strip the stack: ASVS V13.4.6 (Level 3) asks that detailed backend version information is not exposed, including
ServerandX-Powered-Byheaders and default proxy error pages.
What to log: security events with context
OWASP's A09 guidance is to log authentication, access control and server-side input validation failures with enough user context to identify suspicious accounts, and to log every security control whether it succeeds or fails. ASVS 5.0 turns this into testable requirements: V16.3.1 (all authentication operations, success and failure), V16.3.2 (failed authorisation, and at Level 3 all authorisation decisions including sensitive data access), V16.3.3 (attempts to bypass controls such as validation, business logic and anti-automation) and V16.3.4 (unexpected errors and control failures such as backend TLS failures).
A shared vocabulary
The OWASP Logging Vocabulary Cheat Sheet proposes standard event names in the form prefix_event:fields, which makes detection rules portable across applications. Useful examples include authn_login_fail, authn_login_lock, authn_token_reuse, authz_fail, authz_change, input_validation_fail, malicious_excess_404, session_use_after_expire, upload_validation, sys_crash and sys_monitor_disabled. Publish one vocabulary and lint for it in code review.
Required fields
| Question | Fields | Notes |
|---|---|---|
| When | Event time and log time in ISO 8601, UTC or explicit offset | ASVS V16.2.2 requires synchronised time sources and recommends UTC |
| Where | Application ID and version, host, service, entry point (route), code location | Version ties the event to a deployment for rollback decisions |
| Who | Authenticated principal (human or machine), source IP, client ID or API key identifier, session or token identifier in hashed form | Machine callers need a stable identifier, never the secret itself |
| What | Event name, outcome, severity, object or resource, reason | Use the agreed vocabulary; add a security-relevant flag |
| Correlation | Request ID, trace ID, correlation ID returned to the client | Links the client's error report to the full server record |
Do not log everything: the Logging Cheat Sheet warns of "alarm fog", and A10 recommends summarising repeated identical errors. ASVS V16.1.1 asks for an inventory of what each layer logs, in which format, where it is stored, who can access it and for how long.
What never to log, and how to stop it
CWE-532 findings usually come from debug logging that was never removed. ASVS V16.2.5 requires logging to respect data protection levels: credentials and payment details must not be logged, and items such as session tokens only in hashed or masked form.
| Data | Rule | Technique |
|---|---|---|
| Passwords, OTPs, recovery codes | Never log | Exclude at the model level (annotate fields as sensitive) so serialisers skip them |
| Session IDs, access and refresh tokens, API keys | Never log in clear | Log a keyed hash or the key identifier (for example the first characters of a key ID, not the secret) |
| Connection strings, encryption keys, cloud credentials | Never log | Redact in the logging library and block in CI with secret scanners on log fixtures |
| Payment card data | Never log full PAN or security codes | Truncate or tokenise before the value reaches application code |
| Personal data | Minimise, with a legal basis | Pseudonymise user IDs; document retention |
| Request and response bodies | Off by default in production | Allow per route, with field-level redaction, for a time-boxed investigation |
- Redact centrally: implement masking in a logging filter or processor (for example a structured logging processor or appender) so individual developers cannot forget it.
- Watch HTTP client and ORM debug logging: outbound request logging often captures
Authorizationheaders, and ORM debug output captures bound parameters. Keep these at a level that is disabled in production. - Error trackers are logs too: crash reporting SDKs capture local variables, breadcrumbs and request data. Configure their scrubbing rules and apply the same "never log" list.
Leaked tokens in logs and reports are a recurring NHI exposure path; see the OWASP NHI Top 10 NHI2 Secret Leakage Guide.
Log injection and the logging pipeline as attack surface
CWE-117 (Improper Output Neutralization for Logs) covers user input written to logs without neutralising special elements. MITRE lists the consequences as forged entries, hidden activity, corrupted formats that break automated processing, and exploitation of vulnerabilities in log processing tools. The OWASP Logging Cheat Sheet notes that parameterised logging alone does not stop CR and LF injection in Java; a structured encoder that escapes values does.
- Emit structured logs: JSON (or another typed format) with values escaped by the encoder makes newline forging ineffective and satisfies ASVS V16.2.4 (logs readable by the log processor) and V16.4.1 (encoding to prevent log injection).
- Disable interpretation in the logger: Log4Shell (CVE-2021-44228, CVSS 10.0, in the CISA KEV catalog with known ransomware use) showed that a logging library that evaluates lookups in logged messages turns every logged header into code execution. Apache's advisory lists fixed versions 2.15.0 (Java 8), 2.12.2 (Java 7) and 2.3.1 (Java 6); the follow-up CVE-2021-45046 needed 2.16.0 or 2.12.3 because Thread Context (MDC) lookups were still reachable. Keep logging libraries in your software inventory and patch them like any internet-facing component.
- Treat log and error telemetry as untrusted on the way out: dashboards that render log fields need output encoding, and AI agents that read error trackers can be steered by planted content. The Sentry MCP Agentjacking case showed researchers using a public write-only DSN to post fake error reports whose "resolution" an AI coding agent then executed.
Protecting, shipping and alerting on application logs
Logs that live only on the compromised host can be deleted by the attacker (ATT&CK T1070 Indicator Removal) or silenced by disabling the agent (T1685 Disable or Modify Tools). ASVS V16.4.2 requires that logs are protected from unauthorised access and cannot be modified, and V16.4.3 that they are transmitted securely to a logically separate system.
- Ship immediately: write to stdout or a local buffer and forward over TLS (for example syslog over TLS or an authenticated collector endpoint) to a store the application identity cannot delete from.
- Use append-only or immutable storage for audit trails: OWASP's A09 prevention list names append-only database tables for transaction audit records; object storage with retention locks serves the same purpose for log archives.
- Separate the writer identity: the application's log shipping credential should be write-only, scoped to its own stream and rotated like any other machine credential. See the Secrets Management Guide.
- Alert on silence: a source that stops sending is an event. Log
sys_monitor_disabledand alert when expected volume drops to zero. - Build use cases, not only storage: A09 asks for monitoring use cases and response playbooks so the SOC can act. Start with the detections in the table below.
| Application signal | Example detection | Likely meaning |
|---|---|---|
authn_login_fail across many accounts from one source | More than N distinct usernames per IP per 10 minutes | Password spraying or credential stuffing |
authz_fail on sequential object IDs | One principal failing on many object IDs | Broken object level authorisation probing |
input_validation_fail bursts plus 5xx spikes | Validation failures and 500s on one route from one client | Injection testing or fuzzing (often T1190 precursors) |
malicious_excess_404 | High 404 ratio per client | Content discovery or vulnerability scanning |
authn_token_reuse, session_use_after_expire | Any occurrence | Stolen token or replay |
For pipeline design and retention see the SIEM Guide and the NIST SP 800-92 Log Management Guide.
Implementation plan
- Inventory (week 1 to 2): list every application's error handlers, logging libraries and versions, log destinations and error tracking SDKs. This is the ASVS V16.1.1 log inventory.
- Close disclosure first: confirm debug modes and developer exception pages are off in production (ASVS V13.4.2), set framework error properties explicitly, and remove version headers. These are configuration changes with low regression risk.
- Introduce a shared error and logging library: one package per language that provides the global handler, RFC 9457 responses, correlation IDs, the event vocabulary, redaction and a structured encoder. A10 asks for error handling centralised and applied the same way across the organisation.
- Pilot on two services: one high-traffic, one high-sensitivity. Run the new redaction in report mode first (count what would be masked), compare log volumes, and confirm detections still fire.
- Enforce in CI: add static analysis rules for empty catch blocks, catch-all handlers that continue, string-concatenated log messages and logging of fields named like secrets. Fail the build on new findings only, then burn down the backlog.
- Test failure modes: simulate full disks, unreachable log collectors, logging library exceptions and dependency timeouts. The application must keep running without leaking information when logging fails.
- Roll out by service tier, with rollback: ship the library behind a configuration flag so a service can revert to its previous handler in minutes if response formats break clients. Keep the old format available for one release for API consumers.
- Wire detections and playbooks: agree the first five use cases with the SOC, document the response, and run a tabletop using the correlation ID path from client error to server log.
Decision guidance
- Problem details or a custom error schema: choose RFC 9457 for new APIs because clients and gateways increasingly understand it; keep an existing schema only where changing it would break contracted clients, and add a correlation ID to it.
- Library-level redaction or pipeline redaction: do both. Library-level redaction stops secrets leaving the process; collector-side redaction catches what libraries miss. Relying on the pipeline alone means secrets sit in local buffers and in any second destination.
- Log all authorisation decisions or failures only: ASVS Level 2 asks for failures; Level 3 (high-value applications) for all decisions and sensitive data access.
- Small versus large organisations: small teams can rely on the framework's built-in handler, structured logging to a managed service and three alerts (authentication failure spikes, 5xx spikes, log silence); large organisations should publish the shared library and vocabulary as a paved road and measure adoption per service.
Detection and measurement
- Disclosure rate: percentage of 4xx and 5xx responses in DAST and production sampling that contain stack traces, SQL fragments, file paths or version strings. Target zero.
- Security event coverage: share of services emitting the agreed authentication, authorisation and validation events to the central store (ASVS V16.3.1 to V16.3.3).
- Secrets in logs: findings per month from secret scanning run against sampled log streams and error tracker events. The trend should fall to near zero.
- Time to detect in tests: time from a test action (credential stuffing simulation, or access to a honeytoken that OWASP A09 recommends planting) to an alert.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| OWASP Top 10 2025 | A09:2025, A10:2025 | Logging and alerting failures; mishandling of exceptional conditions |
| OWASP ASVS 5.0 | V16.1.1, V16.2.1 to V16.2.5, V16.3.1 to V16.3.4, V16.4.1 to V16.4.3, V16.5.1 to V16.5.4, V13.4.2, V13.4.6 | Testable requirements for inventory, content, events, protection and error handling |
| NIST SP 800-53 Rev. 5 | AU-2 Event Logging, AU-3 Content of Audit Records, AU-6 Audit Record Review, Analysis, and Reporting, AU-9 Protection of Audit Information, AU-12 Audit Record Generation, SI-11 Error Handling, SC-24 Fail in Known State, SI-17 Fail-safe Procedures | Control baseline for audit content, protection and error handling |
| NIST CSF 2.0 | PR.PS-04, DE.CM-09, DE.AE-03 | Log records generated for monitoring; runtime monitoring; correlation |
| CIS Controls v8.1 | Control 8 Audit Log Management; Control 16 Application Software Security | Collection and centralisation; secure coding practices |
| ISO/IEC 27001:2022 Annex A | A.8.15 Logging, A.8.16 Monitoring activities, A.8.17 Clock synchronisation, A.8.28 Secure coding | Management system controls |
| MITRE ATT&CK v20 | T1070 Indicator Removal, T1685 Disable or Modify Tools, T1190 Exploit Public-Facing Application | Log tampering, sensor disabling, and the exploitation attempts good application logs reveal |
Common failure patterns
- Catch, log, continue: an exception in a validation or authorisation helper is logged at WARN and the request proceeds. Fix by making security helpers return explicit allow results and treating any exception as deny.
- Debug left on: a framework debug flag or developer exception page reaches production through a misnamed environment variable. Fix with a startup check that refuses to boot in production with debug enabled.
- Secrets in logs and error trackers: outbound HTTP debug logging records bearer tokens, or a crash reporter captures environment variables. Fix with central redaction, scrubbing rules and secret scanning of log samples.
- Logs only on the box: the application writes to a local file, rotation deletes evidence after days, and an intruder can edit it. Fix by shipping to a separate, write-only destination with retention controls.
Practitioner checklist
- Confirm debug modes, developer exception pages and version headers are disabled in every production deployment.
- Implement one global handler per service that returns RFC 9457 problem details with a correlation ID and no internals.
- Review authorisation, validation and payment code for catch-and-continue paths; make every exception path deny and roll back.
- Adopt a shared event vocabulary and log all authentication, authorisation failures, validation failures and control failures with who, what, where and when in UTC.
- Enforce structured logging with an escaping encoder and constant message templates; cap field lengths.
- Apply a central "never log" list for credentials, tokens, keys and payment data across loggers, HTTP clients, ORMs and error trackers.
- Ship logs off host over TLS to a store the application cannot modify; alert when a source goes silent.
- Keep logging libraries in the software inventory and patch them on the same timeline as internet-facing components.
- Test logging and error handling under failure: full disk, collector down, dependency timeout, injected CR and LF.
- Track disclosure rate, event coverage, secrets-in-logs findings and time to detect, and review them quarterly.
Standards and references
- OWASP: A09:2025 Security Logging and Alerting Failures
- OWASP: A10:2025 Mishandling of Exceptional Conditions
- OWASP: Application Security Verification Standard 5.0
- OWASP: Logging Cheat Sheet
- OWASP: Error Handling Cheat Sheet
- IETF: RFC 9457 Problem Details for HTTP APIs
- MITRE CWE: CWE-117 Improper Output Neutralization for Logs
- Apache Logging Services: Log4j Security Vulnerabilities
Related NHI Mgmt Group resources: OWASP Top 10 A09 Guide · OWASP Top 10 A10 Guide · Log Management and Retention Guide · Secure Coding Guide · Secure File Upload Handling Guide