Main Content

CWE Rule 434

R2026b

Unrestricted Upload of File with Dangerous Type

Since R2026b

Description

Unrestricted Upload of File with Dangerous Type

Polyspace Implementation

The rule checker checks for Use of unsanitized tainted filename.

Examples

expand all

Issue

Unrestricted upload of file with dangerous type occurs when a filename obtained from an untrusted source reaches a sensitive function such as fopen or system without validation or sanitization. The checker requires you to specify taint sources and sanitizers in a -code-behavior-specifications datalog file.

Risk

Using tainted file names with sensitive functions without sanitizing them can result in system vulnerabilities. For example:

  • An attacker can upload files with executable extensions (such as .sh or .php) and trigger their execution on a server.

  • An attacker can use path traversal sequences in filenames to overwrite critical system files.

  • Malicious files stored in web-accessible directories can be served to other users.

Fix

Sanitize uploaded filenames before using them with sensitive functions:

  • Validate file extensions against an allowlist of permitted types.

  • Verify file content matches the declared type.

  • Store uploaded files outside executable directories.

Specify the sanitizing function in your -code-behavior-specifications file so that Polyspace® recognizes the data as sanitized after the function call.

Example — Tainted filename passed to fopen() and system()

In this example, the function get_uploaded_filename is a taint source. The tainted filename flows to fopen and system without sanitization. Polyspace reports violations.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern const char *get_uploaded_filename(void);
extern const unsigned char *get_uploaded_content(size_t *len);

static const char *upload_dir(void) { return "uploads"; }

int save_upload(void)
{
    const char *name = get_uploaded_filename();
    const unsigned char *buf;
    size_t len;
    char path[128];
    FILE *fp;

    buf = get_uploaded_content(&len);
    snprintf(path, sizeof(path), "%s/%s", upload_dir(), name);

    fp = fopen(path, "wb");  // Noncompliant
    if (!fp) return 0;
    fwrite(buf, 1U, len, fp);
    fclose(fp);

    system(path);  // Noncompliant
    return 1;
}

To specify the function as a taint source, specify this datalog code as a .dl file input to the option -code-behavior-specifications:

.include "models/interfaces/cwe434.dl"

Custom_CWE_434.Basic.taintSource(
  "get_uploaded_filename",
  $OutReturnDeref(),
  "User-controlled upload filename!"
).
Alias.Basic.allocates("get_uploaded_filename", $OutReturnValue()).

Custom_CWE_434.specificationFile(__FILE__).

This datalog code specifies that the filename returned by get_uploaded_filename is tainted. It flows through snprintf into path, which is then passed to fopen and system. An attacker can supply a malicious filename such as "malicious.sh" to execute arbitrary code on the server.

Correction — Sanitize filename before use

One possible correction is to pass the filename through a sanitizing function that generates a safe server-side name. In this code, the tainted file name is sanitized using the function make_server_filename.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern const char *get_uploaded_filename(void);
extern const unsigned char *get_uploaded_content(size_t *len);
extern void make_server_filename(char *out, size_t out_sz, const char *ext);

static const char *upload_dir(void) { return "data_uploads"; }

static int has_allowed_ext(const char *name)
{
    const char *dot = strrchr(name, '.');
    if (!dot || dot == name) return 0;
    return (strcmp(dot, ".png") == 0 || strcmp(dot, ".txt") == 0);
}

int save_upload(void)
{
    const char *name = get_uploaded_filename();
    const unsigned char *buf;
    size_t len;
    char safe_name[64];
    char path[128];
    const char *dot;
    FILE *fp;

    if (!has_allowed_ext(name)) return 0;

    dot = strrchr(name, '.');
    make_server_filename(safe_name, sizeof(safe_name), dot);
    buf = get_uploaded_content(&len);
    snprintf(path, sizeof(path), "%s/%s", upload_dir(), safe_name);

    fp = fopen(path, "wb");  // Compliant
    if (!fp) return 0;
    fwrite(buf, 1U, len, fp);
    fclose(fp);
    return 1;
}

To specify the sanitizing function, specify this datalog code as a .dl file input to the option -code-behavior-specifications

.include "models/interfaces/cwe434.dl"

Custom_CWE_434.Basic.taintSource(
  "get_uploaded_filename",
  $OutReturnDeref(),
  "User-controlled upload filename!"
).
Alias.Basic.allocates("get_uploaded_filename", $OutReturnValue()).

Custom_CWE_434.Basic.sanitizing(
  "make_server_filename",
  $OutParameterDeref(0)
).

Custom_CWE_434.specificationFile(__FILE__).

Check Information

Category: Handler Errors
PQL Name: std.cwe_native.R434

Version History

Introduced in R2026b