/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh Web access log Triage: medium Known exploited (CISA KEV)

GET /cgi-bin/ Path Traversal Requests in Your Logs (CVE-2021-41773)

Published

An attempt to exploit the Apache HTTP Server path traversal flaw, walking out of /cgi-bin/ with encoded dot segments to reach files — usually /bin/sh — outside the directories the server was configured to serve.

What it looks like

203.0.113.7 - - [18/Oct/2026:03:51:11 +0000] "GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1" 404 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
198.51.100.42 - - [18/Oct/2026:04:12:03 +0000] "GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1" 404 162 "-" "Go-http-client/2.0"

On our own server, the 30 days to 18 October 2026

181

requests · about 6.0 a day

80

source addresses

Most requested variantsRequests
/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh97
/cgi-bin/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%3…84

LogTriage's production API server (Hetzner, Germany): port 22 open to the internet, key-only since 6 October 2026 (password and keyboard-interactive authentication off); nginx in front of the API on ports 80 and 443. Paths as requested, query strings dropped and identifiers redacted; counted weekly from the nginx access log. More in the monthly attack report.

The vulnerability these requests target

CVE-2021-41773 CVSS 3.1 9.8 critical CISA KEV since November 3, 2021

Apache · HTTP Server — Apache HTTP Server Path Traversal Vulnerability

A flaw was found in a change made to path normalization in Apache HTTP Server 2.4.49. An attacker could use a path traversal attack to map URLs to files outside the directories configured by Alias-like directives. If files outside of these directories are not protected by the usual default configuration "require all denied", these requests can succeed. If CGI scripts are also enabled for these aliased pathes, this could allow for remote code execution. This issue is known to be exploited in the wild. This issue only affects Apache 2.4.49 and not earlier versions. The fix in Apache HTTP Server 2.4.50 was found to be incomplete, see CVE-2021-42013.

NVD description, quoted verbatim · published October 5, 2021

CISA required action: Apply updates per vendor instructions.

CVE-2021-42013 CVSS 3.1 9.8 critical CISA KEV since November 3, 2021

Apache · HTTP Server — Apache HTTP Server Path Traversal Vulnerability

It was found that the fix for CVE-2021-41773 in Apache HTTP Server 2.4.50 was insufficient. An attacker could use a path traversal attack to map URLs to files outside the directories configured by Alias-like directives. If files outside of these directories are not protected by the usual default configuration "require all denied", these requests can succeed. If CGI scripts are also enabled for these aliased pathes, this could allow for remote code execution. This issue only affects Apache 2.4.49 and Apache 2.4.50 and not earlier versions.

NVD description, quoted verbatim · published October 7, 2021

CISA required action: Apply updates per vendor instructions.

Sources: NVD and CISA's Known Exploited Vulnerabilities catalog, re-checked weekly.

What the request is

This is a path traversal probe aimed at Apache HTTP Server. The URI starts inside a directory that Apache maps with an Alias-like directive — /cgi-bin/ almost always, sometimes /icons/ — and then climbs out of it with a chain of dot segments before naming a target somewhere else on the filesystem. In the most-requested variant on this server the target is /bin/sh.

The dots are encoded, and that is the whole point. %2e is a percent-encoded ., so the segment .%2e is a .. that does not look like one until it has been decoded. NVD describes the flaw as a change made to path normalization in Apache HTTP Server 2.4.49: an attacker could use a path traversal attack to map URLs to files outside the directories configured by Alias-like directives. If those files are not protected by the usual default configuration require all denied, the requests can succeed, and if CGI scripts are enabled for the aliased paths this could allow remote code execution. NVD records the issue as exploited in the wild, and CISA lists both CVEs in its Known Exploited Vulnerabilities catalog with known ransomware campaign use.

CVE-2021-42013 exists because the fix in 2.4.50 was insufficient. The second counted variant on this page reflects that round: its dots are doubly encoded, so a single decoding pass leaves %2e behind rather than a dot. Both shapes are now fired blindly at everything, years after the patched releases shipped.

Reading the file is the mild outcome. The dangerous one is the request resolving to an executable in a directory that CGI handles, where the bytes that come back are output rather than content. That second step needs a request body, which is why a bare GET like the ones above is the reconnaissance half of the pair — the scanner reads your status code and decides whether to come back.

Who sends it

Undirected, internet-wide scanning. The senders are mass scanners sweeping address ranges for anything that answers on 80 and 443, botnets that chain a successful hit straight into a dropper or a coin miner, and research crawlers cataloguing exposed versions. Nothing about receiving these requests means your organisation was picked out.

User agents prove nothing: some clients announce an HTTP library, many copy a current Chrome string. The shape is the tell — a handful of URIs from one address within a second or two, no Referer, no requests for stylesheets or images, and an immediate move on to other well-known paths such as /.env once the traversal returns 404.

Is your server exposed?

Answer two questions: what status your logs already returned, and what version is really running behind the edge.

# Every cgi-bin / icons request with its status, worst first
awk '$7 ~ /(cgi-bin|icons)/ {print $9, $7}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -rn | head -20

# Anything that was NOT 404/403/400 — this is the list that matters
awk '$7 ~ /(cgi-bin|icons)/ && $9 !~ /^(404|403|400)$/' /var/log/nginx/access.log

# Ask your own host, read only the status code
curl -s -o /dev/null -w '%{http_code}\n' --path-as-is \
  'http://127.0.0.1/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh'

# Which Apache is actually running?
apache2 -v 2>/dev/null || httpd -v 2>/dev/null

# Alias-like directives, CGI handlers and the default deny
grep -RniE 'ScriptAlias|^[[:space:]]*Alias|Require all denied' \
  /etc/apache2 /etc/httpd 2>/dev/null | head -20

Run the curl check with the Host header of each vhost, not just the default one, and repeat it against the upstream Apache directly if nginx is only a reverse proxy. If the version is 2.4.49 or 2.4.50, patching is the work; if it is anything else, confirm that your top-level <Directory /> still carries Require all denied and that CGI is not enabled for aliased paths you do not use. The Apache configuration reference is at httpd.apache.org/docs/2.4/.

How to block it

If nothing behind this server needs CGI, answer the path at the edge and never proxy it:

# No CGI anywhere behind this vhost
location ^~ /cgi-bin/ {
    access_log off;
    return 404;
}

location ^~ /icons/ {
    access_log off;
    return 404;
}

# Encoded dot segments in the raw request line, before any upstream sees them
if ($request_uri ~* "%2e%2e|\.%2e|%252e|%%32%65") {
    return 404;
}

The two rules catch different shapes on purpose. nginx matches location blocks against the decoded, normalised URI, while $request_uri keeps the request line as the client sent it — which is what matters when proxy_pass is configured without a URI part, because nginx then passes the original request URI to the upstream unchanged.

None of this substitutes for the version fix. An edge rule stops the variants you listed; a server still on 2.4.49 or 2.4.50 stays one unlisted encoding away from the same outcome.

Probes that arrive with it

Detect it

MITRE ATT&CK: T1595.002T1190

Frequently Asked Questions

We run nginx, not Apache. Do these requests matter at all?
The two CVEs are flaws in Apache HTTP Server's path normalization, so an nginx-only edge is not vulnerable to them and a 404 means nothing was served. The question worth answering is what sits behind nginx — if any upstream or vhost proxies to Apache, test that host directly rather than assuming the edge protects it.
One of these requests returned something other than 404. What do I do?
Treat a 200 as a file disclosure and, if CGI is enabled for that aliased path, as possible remote code execution until proven otherwise. Pull the Apache access and error logs for the whole session from that address, look for follow-up POST requests to the same URL, check for new files, cron entries and processes on the host, and get the server off 2.4.49 and 2.4.50.
Which Apache versions are actually affected?
Per NVD, CVE-2021-41773 affects only Apache HTTP Server 2.4.49, and CVE-2021-42013 — the incomplete fix shipped in 2.4.50 — affects 2.4.49 and 2.4.50. Earlier releases are explicitly not affected and no later release is listed. Both entries are in the CISA KEV catalog with known ransomware campaign use, which is why the scanning never stops.
Should we block the source addresses?
Little is gained by it. The addresses rotate constantly and the traffic is sprayed at whole ranges rather than aimed at you, so a blocklist becomes maintenance work with no end. Confirm your version and alias configuration first, then drop the request shape cheaply at the edge and stop logging it.

See what else is probing your server

Drop an nginx or Apache access log into the free browser analyzer: secret-file sweeps, exploit probes, scanners and credential stuffing are grouped by source with the evidence lines, and every known probe links back here. Nothing is uploaded.