How to fix flaws of the type CWE 73 External Control of File Name or Path

Why does Veracode Static Analysis look for it?

Attackers will often try to manipulate paths to gain more information about a system or to gain unauthorised access to system or other user files.

How does Veracode Static Analysis look for it?

In general Veracode Static Analysis reports this flaw when:

  1. It searches your binaries for methods that operate on files (like "new File").
  2. It traces every input into the filename to an application entry point.
    Note that this can be from an HTTP request, user supplied data or from a file or database query.
  3. If it can find such a path it will open a flaw.

How can I fix it?

Veracode Static Analysis does not support any Supported Cleansing Function for this flaw.
Flaws of this weakness category will commonly require Mitigation by Design but there are several strategies you can take to encourage Veracode Static Analysis to automatically close flaws of this type.
We will look first at some strategies that remove the risk and that our engine will automatically detect, then we will look at strategies that remove the risk but require Mitigation by Design.

CWE73-DELETE: Delete the code, if unused

Sometimes the code or feature being reported is no longer in use. In this case we would recommend removing it and rescanning. The flaw should no longer be reported.

CWE73-HARDCODE: Hardcode the filepath

Sometimes, the dynamic file name can be replaced with a hardcoded value.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
File f = new File(request.getParameter("fileName"));

Should be changed to:

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-HARDCODE
File f = new File("config.properties");

CWE73-ALLOWLIST: Use a list of hardcoded values

A list of hard-coded, permitted values is a more practical approach, where suitable. When validating against this ‘allow-list’ take the hard-coded value rather than the user-supplied value.

For more information on this strategy see the Community Article: Using an Allow-list in a Way that Static Analysis can Detect

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
public String buildValidAvatarPath(String configPath, HttpServletRequest request) {
    return configPath + "avatar." + request.getParameter("extension");
}

Should be changed to:

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-ALLOWLIST
public String buildValidAvatarPath(String configPath, HttpServletRequest request) {
    String[] allowedExtensions = new String[]{"jpg","gif","png"};
    String extension = "png"; // Default extension
    for (String allowedExtension: allowedExtensions) {
        if (allowedExtension.equals(request.getParameter("extension"))) {
            extension = allowedExtension;
        }
    }
    String path = configPath + "avatar." + extension;
    // See "Note on authorization"
    User user = getCurrentUser();
    if (!userMayAccessFile(user, path)) {
        throw new AuthorizationException("User may not access this file", user);
    }
    return path;
}

Very important here is to use the value from the static String array as this will allow Veracode Static Analysis to trace the input to a static value.

CWE73-NUMERIC: Use a numeric datatype for user input

When files are referenced by numeric identifiers but the application is using strings, consider re-typing to the numeric type or cast to that type so as to validate the correct format for the requested file.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
File f = new File("picture/" + request.getParameter("variantNumber") + ".png");

Should be changed to:

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-NUMERIC
int variantNumber = Integer.parseUnsignedInt(request.getParameter("variantNumber"));
File f = new File("picture/" + variantNumber + ".png");

CWE73-UUID: Using a UUID

Rather than using a file name/path provided directly from a user, consider looking up the identifier in the database and using a numeric based identifier like a Universally Unique IDentifier or UUID.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
File f = new File("picture/" + request.getParameter("username") + ".png");

Should be changed to:

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-UUID
User u = userDao.findByUsername(request.getParameter("username"));
File f = new File("picture/" + u.uuid.toString() + ".png");

CWE73-HASH: Hashing the input

Similar to using a numeric identifier or a UUID, a hash could be computed from the input. This means the file identifier will be a hexadecimal string of characters.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
public String buildAvatarFilePath(HttpServletRequest request) {
    return "picture/" + request.getParameter("username") + ".png";
}

Should be changed to:

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-HASH
public String buildAvatarFilePath(HttpServletRequest request) throws NoSuchAlgorithmException {
    String username = request.getParameter("username");
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] encodedHash = digest.digest(username.getBytes(StandardCharsets.UTF_8));
    String hexHashedUsername = bytesToHex(encodedHash);

    return "picture/" + hexHashedUsername + ".png";
}

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

CWE73-REGEX: Using a simple regex allowlist

Sometimes the file name/path is too dynamic for the above strategies, thus you will need an allowlist and you need a validation routine.

Java code example

Should be changed to:

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-REGEX
// To learn more about the optional @FilePathCleanser attribute please visit:
// https://community.veracode.com/s/article/How-To-Use-Custom-Cleanser
@FilePathCleanser
public static String buildValidAvatarPath(String configPath, String username) {
    if (!username.matches("^[a-zA-Z0-9]{1,255}$")) {
        throw new ValidationException("Invalid username", username);
    }
    String path = configPath + "/" + username + "/avatar.png";
    // See "Note on authorization"
    User user = getCurrentUser();
    if (!userMayAccessFile(user, path)) {
        throw new AuthorizationException("User may not access this file", user);
    }
    return path;
}

This does not automatically close the flaw!

While this code is recommended, it can not currently be automatically verified by Veracode Static Analysis and will require a manual review by someone from your organization (please note that Veracode does not approve or reject mitigation proposals).
If you choose this control, please note the following:

  1. Commit your changes to Source Control, produce a new build and scan this new build with Veracode Static Analysis.
  2. Documenting your control with a Mitigation Proposal.
    You can submit a mitigation proposal through the Veracode Platform, an IDE or through our API. You can learn how to do this in Veracode Documentation. Here is an example mitigation proposal for this control:
    TechniqueM1: Establish and maintain control over all of your inputs.
    SpecificsUsing a regular expression for file name validation. The regex is: “("^[a-zA-Z0-9]{1,255}$"))” Validation is being carried out in {{CHANGEME: Validation.java}}. See also: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-REGEX
    Remaining RiskModifications to code or design may re-introduce security risk, documented security review requirement.
    VerifiedManual Code Review by {{CHANGEME: engineer@example.com}}}, Unit Test at {{CHANGEME: ValidationTestCase.java}}.
  3. Reach out to your Mitigation Approver.
    Once you have proposed a suitable mitigation proposal, reach out (through for example Jira issue, email, chat or Phone) and ask them to review the Mitigation Proposals in the Veracode Platform.
    They can find more information on how to do this in Veracode Documentation.

CWE73-C14N: Build the path, canonicalize and validate

For complex cases with many variable parts or complex input that cannot be easily validated you can also rely on the standard library to canonicalize the input. Canonicalization is the process of transforming multiple possible inputs to a physical, final location after evaluating the path directives e.g. “.”, “../“, “~” etc. For file paths this can be done using APIs like File.getFullPath. This will resolve any relative paths and return the full path. You must then use this canonical form to verify that the file path points to the correct location.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
public File getAvatarFile(HttpServletRequest request) throws IOException {
    // replace imageUploadPath with root dir for allowed uploads, either as a hardcoded string or from configuration.
    String imageUploadPath = "/var/www/images/";
    String path = imageUploadPath + request.getParameter("username") + ".png";
    return path;
}

Should be changed to:

public File getAvatarFile(HttpServletRequest request) throws IOException {
    // replace imageUploadPath with root dir for allowed uploads, either as a hardcoded string or from configuration.
    String imageUploadPath = "/var/www/images/";
    String path = imageUploadPath + request.getParameter("username") + ".png";
    return validateImageUploadPath(imageUploadPath, path);
}

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-C14N
// To learn more about the optional @FilePathCleanser attribute please visit:
// https://community.veracode.com/s/article/How-To-Use-Custom-Cleanser
@FilePathCleanser
public File validateImageUploadPath(String basePath, String path) throws IOException {
    File image = new File(path); // MITIGATED VERACODE STATIC CWE73
    String absolutePath = image.getCanonicalPath();

    if (!absolutePath.startsWith(basePath)) {
        throw new SecurityException(
            "Potential Path Traversal",
                new HashMap<>() {{
                    put("path", path);
                    put("basePath", basePath);
                    put("absolutePath", absolutePath);
                }});
    }

    // See "Note on authorization"
    User user = getCurrentUser();
    if (!userMayAccessFile(user, path)) {
        throw new AuthorizationException("User may not access this file", user);
    }

    return image;
}


C#.NET code example

// WARNING DO NOT USE THIS VULNERABLE CODE
public ActionResult Image(string id)
{
    var basePath = Server.MapPath("/Images");
    var path = Path.Combine(basePath, id + ".jpg");
    return base.File(path, "image/jpeg");
}

Should be changed to:

public ActionResult Image(string id)
{
    var basePath = Server.MapPath("/Images");
    var path = Path.Combine(basePath, id + ".jpg");
    return base.File(validateImageUploadPath(basePath, path), "image/jpeg"); // MITIGATED VERACODE STATIC CWE73
}

// From: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-C14N
// To learn more about the optional @FilePathCleanser attribute please visit:
// https://community.veracode.com/s/article/How-To-Use-Custom-Cleanser
[FilePathCleanser]
private string validateImageUploadPath(string basePath, string path)
{
    string absolutePath = Path.GetFullPath(path);

    if (!absolutePath.StartsWith(basePath))
    {
        throw new CustomSecurityException(
            "Potential path traversal",
            new Dictionary
            {
                { "path", path },
                { "absolutePath", absolutePath }
            });
    }

    // See "Note on authorization"
    if (!userMayAccessFile(this.User, path))
    {
        throw new AuthorizationException("User may not access this file", this.User);
    }

    return absolutePath;
}

 

Does not automatically close the flaw!

While this code is recommended, it can not currently be automatically be verified by Veracode Static Analysis and will require a manual review by someone from your organization (please note that Veracode does not approve or reject mitigation proposals).
If you choose this control, please do the following:

  1. Documenting your control in a Mitigation Proposal.
    You can submit a mitigation proposal through the Veracode Platform, an IDE or through our API. You can learn how to do this in Veracode Documentation. Here is an example mitigation proposal for this control:
    TechniqueM1: Establish and maintain control over all of your inputs.
    SpecificsUsing input validation to ensure value is always in expected range, see also: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-C14N
    Remaining RiskModifications to code or design may re-introduce security risk, documented security review requirement.
    VerifiedManual Review by {{CHANGEME: engineer@example.com}}}, Unit Test at {{CHANGEME: ValidationTestCase.java}}.
  2. Reach out to your Mitigation Approver.
    Once you are done reach out (through for example Jira issue, email, chat or Phone) and ask them to review the Mitigation Proposals in the Veracode Platform.
    They can find more information on how to do this in Veracode Documentation.

CWE73-CONFIG: Use only trusted configuration data

Sometimes you may want to rely on values that change infrequently and so use a trusted configuration store. This is typically stored in a read-only file on disk. Sometimes configuration is stores in a database, this is a more risky strategy unless you have strong controls on database access in place, please verify that only an administrator will be able to change these values.
Veracode Static Analysis does not know which files on disk or which tables in your database are administrator controlled and so requires that you document this in a mitigation proposal.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
String imagePath = request.getParameter("logoFile");
File f = new File(imagePath);

Should be changed to:

Properties prop = new Properties();
try (InputStream configFile = this.getClass().getClassLoader().getResourceAsStream("config.properties")) {
    prop.load(configFile);
}
String imagePath = prop.getProperty("logoFilePath");
File f = new File(imagePath); // MITIGATED VERACODE STATIC CWE73
            

May not automatically close the flaw!

While this code is recommended, it can not currently be automatically be verified by Veracode Static Analysis for non-Web applications and will require a manual review by someone from your organization (please note that Veracode does not approve or reject mitigation proposals).
If you choose this control, please do the following:

  1. Documenting your control in a Mitigation Proposal.
    You can submit a mitigation proposal through the Veracode Platform, an IDE or through our API. You can learn how to do this in Veracode Documentation. Here is an example mitigation proposal for this control:
    TechniqueM1: Establish and maintain control over all of your inputs.
    SpecificsLoading configuration value named {{CHANGEME: logoFilePath}} from {{CHANGEME: config.properties}}. I have verified that this can only be updated by the {{CHANGEME: systems root user}}. See also: https://community.veracode.com/s/article/how-do-i-fix-cwe-73-external-control-of-file-name-or-path-in-java#CWE73-CONFIG
    Remaining RiskModifications to code or design may re-introduce security risk, documented security review requirement.
    VerifiedManual Review by {{CHANGEME: engineer@example.com}}}, Unit Test at {{CHANGEME: ValidationTestCase.java}}.
  2. Reach out to your Mitigation Approver.
    Once you are done reach out (through for example Jira issue, email, chat or Phone) and ask them to review the Mitigation Proposals in the Veracode Platform.
    They can find more information on how to do this in Veracode Documentation.

How should I *not* fix it?

Bad Strategy: Using a (regex) blocklist / denylist / 'filter' / 'sanitizer'

Do not try to block ".." or "." or "/".
While this will make an attackers job more difficult, it is not a complete strategy as attackers may abuse URL decoding and provide paths in the form of "%3F". Or attackers may use symbolic links. Or attackers may simply provide a full path like "/etc/passwd". Or attackers may use special characters like "~" instead.
Future updates to the file system, programming language or application may also make this blocklist out of date.
For more information see the OWASP documentation on Allow list vs block list.
We recommend against the use of blocklists and instead recommend you review this document for other (allowlist) methods.  

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
String fileName = request.getParameter("fileName");

fileName = fileName.replace("../", "");

File f = new File(fileName);

Bad Strategy: HTML encoding the data

HTML encoding is not appropriate for file paths. We recommend against the use of HTML encoding and instead recommend you review this document for other methods.

Java code example

// WARNING DO NOT USE THIS VULNERABLE CODE
String username = ESAPI.encoder().encodeForHTML(request.getParameter("username"));

File f = new File("picture/" + username + ".png");
                

Note on authorization

Strictly speaking correct remediation of CWE 73 does not require that you verify that the given user is allowed to access the given file, however it is still highly advisable to ensure that you verify that the user accessing the file has the authorization to do so.

How you do this is however very application dependent.
Maybe you only have one user and only need to check that the user is logged in. Maybe you have many users that may belong to groups and need to check both the user and group permissions.
For example you may allow public users to read a file, but only administrators to update a file.
Or you may allow users to share files with each other but only have access if it’s explicitly shared.
Keep in mind the principle of least privilege, by default access should be denied.

For more information please see:

None of these strategies work for me, what now?

Most contracts include consultations with, and email support by, the Veracode Application Security Consulting team.
If you are unsure if your contract includes it please contact your companies Veracode administrator.

To contact this team for detailed questions regarding remediation guidance please contact Veracode Support or Schedule a Consultation.

Where can I find more information?

License

Source code on this page is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to https://unlicense.org/

Topics (2)

Related Topics

    Ask the Community

    Get answers, share a use case, discuss your favorite features, or get input from the Community.