Safeguard
Application Security•

CWE-162 Trailing Special Elements: Slashes, Dots and Spaces

A trailing slash, backslash or space can bypass authentication or expose source code. How CWE-162 works and how to fix it with normalization.

Safeguard Security Team
5 min read

CWE-162 is the failure to neutralize trailing special elements, the characters at the end of a value that a downstream component reads in an unexpected way. A single slash, backslash, dot or space at the end of a name can change which rule applies to it.

Web servers, application servers and frameworks that match requests against file types or protected directories are the usual victims. If your authorization or file handling depends on how a path ends, you are in scope. MITRE lists the weakness as not language specific and not technology specific.

How it happens

A rule says that requests ending in a certain extension, or inside a certain directory, need a login or must be run by a handler. An attacker adds a trailing element that the rule does not expect but the file system or server still resolves to the same resource. The rule misses, and the resource is served without its protection.

Three observed examples show the same idea in different forms.

  • CVE-2004-0847 is a web framework for .NET that lets remote attackers bypass authentication for .aspx files in restricted directories with a request containing a backslash or an encoded backslash, written %5C.
  • CVE-2002-1451 is a trailing space, a plus sign in the query string, that leads to source code disclosure.
  • CVE-2001-0446 is an application server that lets remote attackers read source code for .jsp files by appending a slash to the requested URL.

In the last two, the handler that would have executed the page is not selected, so the raw source is returned. In the first, the access check never fires.

A small sketch of the weak pattern shows why this works.

# Vulnerable: protection depends on the exact end of the string
if request_path.endswith(".aspx") and not user.logged_in:
    deny()
else:
    serve(request_path)

A request for the same page with a trailing character no longer ends with the expected extension. The check is skipped, but the server may still map it to the file.

What an attacker gains

The record lists integrity impact as unexpected state. The examples give the concrete results: authentication bypass for protected pages, and disclosure of source code that might contain credentials, logic flaws or internal addresses.

Source disclosure is the quiet one. It rarely looks like an attack in the logs, and the attacker can then study the code offline and plan the next step.

How to find it

MITRE lists no detection methods for this entry. These checks help.

  • For every protected route and every handled file type, request it with a trailing slash, a trailing backslash, an encoded backslash, trailing dots and trailing spaces. The response should match the normal request or be an error, never raw source and never a page that skipped login.
  • Compare what your access control layer sees to what the file layer serves. Any difference is a bypass candidate.
  • Review rules written as string suffix checks or exact string comparisons on request paths.
  • Run dynamic scans against staging. A dynamic scan sends many path variants at real routes, which is the fastest way to see a mismatch.

How to fix it

The mitigation guidance asks for the same mindset as its siblings. Developers should anticipate that trailing special elements will be injected, removed or manipulated in the input vectors of their product, and use a combination of denylists and allowlists so only valid, expected input is processed.

  1. Normalize the path before any decision. Remove trailing separators and dots in the way your platform does, resolve dot segments, and decode once.
  2. Apply authorization to the normalized resource, not to the raw text. Deny by default, so a path that does not match an allow rule is refused.
from posixpath import normpath

def route_key(raw_path: str) -> str:
    cleaned = raw_path.replace("\\", "/").rstrip(" .")
    return normpath(cleaned)

allowed = {"/public/index.html", "/public/about.html"}
if route_key(request_path) not in allowed:
    deny()
  1. Prefer an allowlist of known routes over a list of protected ones. A forgotten variant of a denylist entry is open. A forgotten variant of an allowlist entry is closed.
  2. Keep the layer that makes the access decision and the layer that opens the file in agreement. Best case they are the same code path.
  3. Configure the server so that file type handlers apply to the resolved file and do not depend on how the URL text ends.
  4. Reject malformed requests. A path with a trailing backslash on a platform that does not use one is not a legitimate request.

Try it yourself

A dynamic scan of a sample web app shows how path variants are probed against protected routes.

Click through it at your own pace, or open it full screen.

Check what you inherit

Several observed cases come from servers and frameworks, not from application code. If your stack includes such components, the exposure comes from your dependencies. The free in-browser dependency scan reads a manifest or lockfile of up to 100 dependencies without a login, and the file stays on your machine. Reachability analysis helps you see whether your code calls the affected function.

Quick check

Why does a trailing character expose source code?

The server may no longer match the request to the handler that runs the page, so it serves the file as plain content. CVE-2001-0446 is an example using a trailing slash on a .jsp URL.

Is a denylist of known bad endings enough?

No. Different platforms treat different trailing characters as ignorable. Normalize first and use an allowlist.

Where should the access check run?

On the normalized, resolved resource, at the point where the file or handler is chosen. Checking raw text earlier invites mismatches.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.